├── .gitignore ├── CONTRIBUTING.md ├── LEGAL.md ├── LICENSE ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml ├── ps-bootstrap ├── .gitignore ├── desc_tar.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── alipay │ │ │ └── antchain │ │ │ └── bridge │ │ │ └── pluginserver │ │ │ ├── AntChainBridgePluginServerApplication.java │ │ │ └── config │ │ │ └── PluginManagerConfiguration.java │ └── resources │ │ ├── application.yml │ │ ├── banner.txt │ │ ├── logback-spring.xml │ │ └── scripts │ │ ├── init_tls_certs.sh │ │ ├── plugin-server.service │ │ ├── print.sh │ │ ├── start.sh │ │ └── stop.sh │ └── test │ ├── java │ └── com │ │ └── alipay │ │ └── antchain │ │ └── bridge │ │ └── pluginserver │ │ ├── AntChainBridgePluginManagementApplicationTests.java │ │ └── AntChainBridgePluginServerApplicationTests.java │ └── resources │ ├── application.yml │ └── logback-spring.xml ├── ps-cli ├── .gitignore ├── README.md ├── desc_tar.xml ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── alipay │ │ └── antchain │ │ └── bridge │ │ └── pluginserver │ │ └── cli │ │ ├── command │ │ ├── ArgsConstraint.java │ │ ├── Command.java │ │ ├── CommandHandler.java │ │ ├── CommandNamespace.java │ │ ├── CommandNamespaceImpl.java │ │ ├── ManagementCommandNamespace.java │ │ ├── NamespaceManager.java │ │ └── NamespaceManagerImpl.java │ │ ├── core │ │ └── ManagementGrpcClient.java │ │ └── shell │ │ ├── GlLineReader.java │ │ ├── GroovyScriptCommandNamespace.java │ │ ├── GroovyShellProvider.java │ │ ├── JsonUtil.java │ │ ├── Launcher.java │ │ ├── PromptCompleter.java │ │ ├── ReservedWord.java │ │ ├── Shell.java │ │ └── ShellProvider.java │ └── resources │ ├── VERSION │ ├── logback.xml │ └── scripts │ └── start.sh ├── ps-pluginmanager ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── alipay │ └── antchain │ └── bridge │ └── pluginserver │ └── pluginmanager │ ├── IPluginManagerWrapper.java │ └── PluginManagerWrapperImpl.java ├── ps-server ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── alipay │ └── antchain │ └── bridge │ └── pluginserver │ └── server │ ├── CrossChainServiceImpl.java │ ├── PluginManagementServiceImpl.java │ ├── ResponseBuilder.java │ ├── exception │ └── ServerErrorCodeEnum.java │ └── interceptor │ └── RequestTraceInterceptor.java └── ps-service ├── .gitignore ├── pom.xml └── src └── main └── proto ├── managementserver.proto └── pluginserver.proto /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | 26 | .idea -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | ## Branch Strategy 4 | 5 | We recommend that developers following the rules [here](https://jeffkreeftmeijer.com/git-flow/git-flow.png). 6 | 7 | - Branch `main` with stable code and tags on it. 8 | - Branch `develop` for "next release" development. 9 | - Feature branches start with prefix `feat/` 10 | - Release branches start with prefix `release/` 11 | - Hotfix branches start with prefix `hotfix/` 12 | 13 | ## Contributing 14 | 15 | - Fork the repository or create branches. 16 | - Checkout your branch like a feature or bugfix. 17 | - Make a pull request to the `develop` branch of this repository. 18 | - Wait for review and PR merged. 19 | 20 | --- 21 | 22 | **Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://kcd.im/pull-request) -------------------------------------------------------------------------------- /LEGAL.md: -------------------------------------------------------------------------------- 1 | Legal Disclaimer 2 | 3 | Within this source code, the comments in Chinese shall be the original, governing version. Any comment in other languages are for reference only. In the event of any conflict between the Chinese language version comments and other language version comments, the Chinese language version shall prevail. 4 | 5 | 法律免责声明 6 | 7 | 关于代码注释部分,中文注释为官方版本,其它语言注释仅做参考。中文注释可能与其它语言注释存在不一致,当中文注释与其它语言注释存在不一致时,请以中文注释为准。 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | am logo 3 |

AntChain Bridge Plugin Server

4 |

5 | 6 | pull requests welcome badge 7 | 8 | 9 | Language 10 | 11 | 12 | GitHub contributors 13 | 14 | 15 | License 16 | 17 |

18 |
19 | 20 | > [!CAUTION] 21 | > 本仓库已经废弃,请转到[AntChainBridge](https://github.com/AntChainOpenLabs/AntChainBridge) 22 | 23 | # 介绍 24 | 25 | AntChain Bridge 插件服务(PluginServer, PS)用于管理异构链插件、完成与中继通信的工作。 26 | 27 | - **插件管理能力** 28 | 29 | 在开发者完成一个异构链插件开发之后,将该插件打包放到PS的指定路径之下,启动PS即可加载该插件,PS将完成插件和区块链桥接组件(Blockchain Bridge Component, BBC)对象的管理等工作,PS还提供了CLI工具完成诸如插件重新加载、停止等工作。 30 | 31 | - **与中继通信** 32 | 33 | 将PS注册到一个中继之后,PS会作为一个RPC Server为中继提供服务,PS和中继之间会建立双向认证的TLS连接,确保身份互认和安全性,中继会发送请求要求PS完成BBC对象初始化等工作,并调用BBC的接口,完成与异构链的交互。 34 | 35 | # 架构 36 | 37 | 下面介绍了中继服务的整体架构。 38 | 39 | **以下插件BCOS和插件ChainMaker均为展示用例,代表不同的异构插件实现* 40 | 41 | 42 | 43 | # 快速开始 44 | 45 | ## 构建 46 | 47 | 进入代码的根目录,运行mvn编译即可: 48 | 49 | ```shell 50 | mvn clean package 51 | ``` 52 | 53 | 产生的安装包在`ps-bootstrap/target/plugin-server-x.x.x.tar.gz`。 54 | 55 | ## 配置 56 | 57 | 在获得安装包之后,执行解压缩操作,这里以`plugin-server-x.x.x.tar.gz`为例。 58 | 59 | ``` 60 | tar -zxf plugin-server-x.x.x.tar.gz 61 | ``` 62 | 63 | 进入解压后的目录,可以看到: 64 | 65 | ``` 66 | cd plugin-server/ 67 | tree . 68 | . 69 | ├── README.md 70 | ├── bin 71 | │   ├── init_tls_certs.sh 72 | │   ├── plugin-server.service 73 | │   ├── print.sh 74 | │   ├── start.sh 75 | │   └── stop.sh 76 | ├── config 77 | │   └── application.yml 78 | └── lib 79 | └── ps-bootstrap-x.x.x.jar 80 | 81 | 82 | 3 directories, 8 files 83 | ``` 84 | 85 | 首先,初始化PS的TLS秘钥和证书,该脚本将会在项目根目录下创建文件夹`certs`,下面存储了私钥`server.key`、证书`server.crt`、信任的证书`trust.crt`。 86 | 87 | ``` 88 | ./bin/init_tls_certs.sh 89 | ``` 90 | 91 | 然后,在和中继建立连接之前,中继的运维人员应该将中继的证书发送给了您,比如`relayer.crt`,您需要将这个证书添加到`trust.crt`中。 92 | 93 | ``` 94 | cat relayer.crt >> trust.crt 95 | ``` 96 | 97 | 最后修改您的配置文件,将证书目录配置进去。 98 | 99 | ``` 100 | vi config/application.yml 101 | ``` 102 | 103 | 依次替换`grpc.server.security.certificate-chain`、`grpc.server.security.private-key`和`grpc.server.security.trustCertCollection`的配置项。 104 | 下面给出一个例子,示例中诸如`/path/to/certs/server.crt`的具体配置属性值请替换为您的实际路径,`file:`保留: 105 | 106 | ```yaml 107 | grpc: 108 | server: 109 | security: 110 | # server certificate 111 | certificate-chain: file:/path/to/certs/server.crt 112 | # server key 113 | private-key: file:/path/to/certs/server.key 114 | # Mutual Certificate Authentication 115 | trustCertCollection: file:/path/to/certs/trust.crt 116 | ``` 117 | 118 | 然后修改插件库路径,PS将加载这个路径下的插件。修改配置项`pluginserver.plugin.repo`,比如: 119 | 120 | ```yaml 121 | pluginserver: 122 | plugin: 123 | # where to load the hetero-chain plugins 124 | repo: /path/to/plugins 125 | ``` 126 | 127 | 将您的插件都放到这个路径下即可。 128 | 129 | ## 运行 130 | 131 | ### 作为系统服务运行 132 | 133 | 在解压包根目录之下,可以找到`start.sh`脚本。 134 | 135 | 如下可以打印帮助信息: 136 | 137 | ``` 138 | ./bin/start.sh -h 139 | 140 | start.sh — Start the plugin server 141 | 142 | Usage: 143 | start.sh 144 | 145 | Examples: 146 | 1. start in system service mode: 147 | start.sh -s 148 | 2. start in application mode: 149 | start.sh 150 | 151 | Options: 152 | -s run in system service mode. 153 | -h print help information. 154 | ``` 155 | 156 | 运行如下命令,会自动将插件服务启动为系统服务: 157 | 158 | ``` 159 | ./bin/start.sh -s 160 | ``` 161 | 162 | 看到下面的输出即启动成功: 163 | 164 | ``` 165 | ___ __ ______ __ _ ____ _ __ 166 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 167 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 168 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 169 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 170 | /____/ 171 | 172 | [ INFO ]_[ 2023-06-20 20:57:06.168 ] : running in system service mode 173 | [ INFO ]_[ 2023-06-20 20:57:06.168 ] : plugin-server started successfully 174 | ``` 175 | 176 | 可以通过下面命令查看系统服务状态: 177 | 178 | ``` 179 | systemctl status plugin-server.service 180 | ``` 181 | 182 | ### 作为普通进程运行 183 | 184 | 在解压包根目录之下,运行一下命令即可: 185 | 186 | ``` 187 | ./bin/start.sh 188 | ``` 189 | 190 | 看到下面的输出即启动成功: 191 | 192 | ``` 193 | ___ __ ______ __ _ ____ _ __ 194 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 195 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 196 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 197 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 198 | /____/ 199 | 200 | [ INFO ]_[ 2023-03-30 15:11:27.1680160287 ] : start plugin-server now... 201 | [ INFO ]_[ 2023-03-30 15:11:27.1680160287 ] : plugin-server started successfully 202 | ``` 203 | 204 | 可以通过`bin/stop.sh`关闭服务。 205 | 206 | 日志文件存储在`log`目录之下。 207 | 208 | ## 插件 209 | 210 | 将你的插件放在配置`pluginserver.plugin.repo`的路径之下,然后启动插件服务即可加载所有插件。 211 | 212 | 插件运行中使用`BBCLogger`打印的日志,比如[这里](https://github.com/AntChainOpenLabs/AntChainBridgePluginSDK/blob/604c5b97305ee77cfa1e14454f5b99f1f905f6ea/pluginset/ethereum/offchain-plugin/src/main/java/com/alipay/antchain/bridge/plugins/ethereum/EthereumBBCService.java#L74),插件服务将会按照插件的`product`和BBCService对象的`domain`,打印到不同文件`logs/bbc/${product}/${domain}`,比如下面`product`为`simple-ethereum`和域名为`domainB`的日志文件。 213 | 214 | ``` 215 | logs/ 216 | ├── antchain-bridge-pluginserver 217 | │   ├── application.log 218 | │   └── error.log 219 | └── bbc 220 | └── simple-ethereum 221 | └── domainB.log 222 | 223 | 3 directories, 3 files 224 | ``` 225 | 226 | ## 运行测试 227 | 228 | 在运行测试之前,请使用`ps-bootstrap/src/main/resources/scripts/init_tls_certs.sh`生成证书,并将`server.key`和`server.crt` 放到`ps-bootstrap/src/test/resources`之下,运行下述命令即可运行测试用例: 229 | 230 | ``` 231 | mvn test 232 | ``` 233 | 234 | # CLI 235 | 236 | CLI工具在[v0.2.0](https://github.com/AntChainOpenLab/AntChainBridgePluginServer/releases/tag/v0.2.0)版本已经发布,相关教程请参考[文档](https://github.com/AntChainOpenLab/AntChainBridgePluginServer/blob/main/ps-cli/README.md)。 237 | 238 | 239 | # 社区治理 240 | 241 | AntChain Bridge 欢迎您以任何形式参与社区建设。 242 | 243 | 您可以通过以下方式参与社区讨论 244 | 245 | - 钉钉 246 | 247 | ![scan dingding](https://antchainbridge.oss-cn-shanghai.aliyuncs.com/antchainbridge/document/picture/dingding2024.png?x-oss-process=image/resize,w_400/quality,Q_100) 248 | 249 | - 邮件 250 | 251 | 发送邮件到`antchainbridge@service.alipay.com` 252 | 253 | # License 254 | 255 | 详情参考[LICENSE](./LICENSE)。 256 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.18 9 | 10 | 11 | pom 12 | 13 | ps-bootstrap 14 | ps-service 15 | ps-server 16 | ps-pluginmanager 17 | ps-cli 18 | 19 | 20 | 21 | 8 22 | 0.2.3 23 | 2.15.0.RELEASE 24 | 2.0.59.Final 25 | 3.19.1 26 | 0.6.1 27 | 1.62.2 28 | 1.3.5 29 | 4.13.2 30 | 0.2.2 31 | 3.3.0 32 | 3.0.17 33 | 1.5.0 34 | 5.8.26 35 | 1.2.83_noneautotype 36 | 3.10.0 37 | 1.7.28 38 | 2.0.0 39 | 2.2 40 | 1.2.13 41 | ${settings.localRepository}/org/mortbay/jetty/alpn/jetty-alpn-agent/${jetty.alpnAgent.version}/jetty-alpn-agent-${jetty.alpnAgent.version}.jar 42 | 43 | 44 | 45 | 46 | github 47 | https://maven.pkg.github.com/AntChainOpenLab/* 48 | 49 | true 50 | 51 | 52 | 53 | 54 | com.alipay.antchain.bridge 55 | antchain-bridge-pluginserver 56 | 0.2.3 57 | 58 | antchain-bridge-pluginserver 59 | antchain-bridge-pluginserver 60 | 61 | 62 | 63 | 64 | net.devh 65 | grpc-server-spring-boot-starter 66 | ${grpc-starter.version} 67 | 68 | 69 | io.netty 70 | netty-tcnative-boringssl-static 71 | ${netty-tcnative-boringssl-static.version} 72 | 73 | 74 | io.grpc 75 | grpc-core 76 | ${grpc.version} 77 | 78 | 79 | io.grpc 80 | grpc-inprocess 81 | ${grpc.version} 82 | 83 | 84 | io.grpc 85 | grpc-services 86 | ${grpc.version} 87 | 88 | 89 | io.grpc 90 | grpc-api 91 | ${grpc.version} 92 | 93 | 94 | io.grpc 95 | grpc-netty-shaded 96 | ${grpc.version} 97 | 98 | 99 | io.grpc 100 | grpc-stub 101 | ${grpc.version} 102 | 103 | 104 | io.grpc 105 | grpc-protobuf 106 | ${grpc.version} 107 | 108 | 109 | 110 | jakarta.annotation 111 | jakarta.annotation-api 112 | ${jakarta.annotation-api.version} 113 | true 114 | 115 | 116 | com.alipay.antchain.bridge 117 | ps-service 118 | ${pluginserver.version} 119 | 120 | 121 | com.alipay.antchain.bridge 122 | ps-server 123 | ${pluginserver.version} 124 | 125 | 126 | com.alipay.antchain.bridge 127 | ps-pluginmanager 128 | ${pluginserver.version} 129 | 130 | 131 | com.alipay.antchain.bridge 132 | antchain-bridge-plugin-manager 133 | ${antchain-bridge.sdk.version} 134 | 135 | 136 | com.alipay.antchain.bridge 137 | antchain-bridge-spi 138 | ${antchain-bridge.sdk.version} 139 | 140 | 141 | com.alipay.antchain.bridge 142 | antchain-bridge-commons 143 | ${antchain-bridge.sdk.version} 144 | 145 | 146 | org.pf4j 147 | pf4j 148 | ${pf4j.version} 149 | 150 | 151 | com.alipay.antchain.bridge 152 | antchain-bridge-plugin-lib 153 | ${antchain-bridge.sdk.version} 154 | 155 | 156 | org.slf4j 157 | slf4j-api 158 | ${slf4j.version} 159 | 160 | 161 | org.slf4j 162 | slf4j-simple 163 | ${slf4j.version} 164 | 165 | 166 | org.jline 167 | jline 168 | ${jline.version} 169 | 170 | 171 | org.codehaus.groovy 172 | groovy-all 173 | ${groovy.version} 174 | pom 175 | 176 | 177 | commons-cli 178 | commons-cli 179 | ${commons-cli.version} 180 | 181 | 182 | cn.hutool 183 | hutool-all 184 | ${hutool.version} 185 | 186 | 187 | com.alibaba 188 | fastjson 189 | ${fastjson.version} 190 | 191 | 192 | 193 | 194 | 195 | 196 | org.yaml 197 | snakeyaml 198 | ${snake.yaml.version} 199 | 200 | 201 | ch.qos.logback 202 | logback-core 203 | ${logback.classic.version} 204 | 205 | 206 | ch.qos.logback 207 | logback-classic 208 | ${logback.classic.version} 209 | 210 | 211 | ch.qos.logback 212 | logback-core 213 | 214 | 215 | 216 | 217 | 218 | org.springframework.boot 219 | spring-boot-starter 220 | 221 | 222 | org.yaml 223 | snakeyaml 224 | 225 | 226 | ch.qos.logback 227 | logback-classic 228 | 229 | 230 | 231 | 232 | org.projectlombok 233 | lombok 234 | true 235 | 236 | 237 | org.springframework.boot 238 | spring-boot-starter-test 239 | test 240 | 241 | 242 | 243 | 244 | 245 | 246 | org.apache.maven.plugins 247 | maven-compiler-plugin 248 | ${maven-compiler-plugin.version} 249 | 250 | ${java.version} 251 | ${java.version} 252 | UTF-8 253 | -XDignore.symbol.file 254 | 255 | 256 | 257 | org.apache.maven.plugins 258 | maven-source-plugin 259 | ${maven-source-plugin.version} 260 | 261 | 262 | attach-sources 263 | 264 | jar-no-fork 265 | 266 | 267 | 268 | 269 | 270 | org.apache.maven.plugins 271 | maven-surefire-plugin 272 | 3.0.0-M5 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /ps-bootstrap/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /ps-bootstrap/desc_tar.xml: -------------------------------------------------------------------------------- 1 | 4 | ${version} 5 | 6 | tar.gz 7 | 8 | true 9 | 10 | 11 | ${project.basedir}/../target/boot 12 | ${file.separator}lib 13 | 14 | ${artifactId}-${version}.jar 15 | 16 | 17 | 18 | ${project.basedir}/src/main/resources/scripts 19 | ${file.separator}bin 20 | 21 | *.sh 22 | plugin-server.service 23 | 24 | 25 | 26 | ${project.basedir}/src/main/resources 27 | ${file.separator}config 28 | 29 | application.yml 30 | 31 | 32 | 33 | ${project.basedir}/../ 34 | ${file.separator} 35 | 36 | README.md 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ps-bootstrap/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alipay.antchain.bridge 8 | antchain-bridge-pluginserver 9 | 0.2.3 10 | 11 | 12 | ps-bootstrap 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | com.alipay.antchain.bridge 23 | ps-server 24 | 25 | 26 | com.alipay.antchain.bridge 27 | ps-pluginmanager 28 | 29 | 30 | 31 | 32 | 33 | 34 | src/main/resources 35 | 36 | **/application.yml 37 | **/*.xml 38 | **/banner.txt 39 | 40 | 41 | true 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-deploy-plugin 48 | 2.7 49 | 50 | true 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | 62 | 63 | ../target/boot 64 | 65 | 66 | 67 | 68 | repackage 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-resources-plugin 76 | 77 | 78 | jks 79 | 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-assembly-plugin 85 | 3.1.0 86 | 87 | 88 | 89 | plugin-server 90 | 91 | desc_tar.xml 92 | 93 | 94 | make-tar 95 | package 96 | 97 | single 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/java/com/alipay/antchain/bridge/pluginserver/AntChainBridgePluginServerApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver; 18 | 19 | import org.springframework.boot.WebApplicationType; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | import org.springframework.boot.builder.SpringApplicationBuilder; 22 | 23 | @SpringBootApplication(scanBasePackages = {"com.alipay.antchain.bridge.pluginserver"}) 24 | public class AntChainBridgePluginServerApplication { 25 | 26 | public static void main(String[] args) { 27 | new SpringApplicationBuilder(AntChainBridgePluginServerApplication.class) 28 | .web(WebApplicationType.NONE) 29 | .run(args); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/java/com/alipay/antchain/bridge/pluginserver/config/PluginManagerConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.config; 18 | 19 | import java.io.IOException; 20 | import java.net.InetAddress; 21 | import java.net.InetSocketAddress; 22 | 23 | import cn.hutool.core.util.StrUtil; 24 | import com.alipay.antchain.bridge.pluginserver.server.PluginManagementServiceImpl; 25 | import io.grpc.Server; 26 | import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; 27 | import lombok.extern.slf4j.Slf4j; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.beans.factory.annotation.Value; 30 | import org.springframework.context.annotation.Bean; 31 | import org.springframework.context.annotation.Configuration; 32 | 33 | @Configuration 34 | @Slf4j 35 | public class PluginManagerConfiguration { 36 | 37 | @Value("${pluginserver.managerserver.host:localhost}") 38 | private String managementHost; 39 | 40 | @Value("${pluginserver.managerserver.port}") 41 | private String pluginServerMgrPort; 42 | 43 | @Bean 44 | public Server pluginMgrServer(@Autowired PluginManagementServiceImpl pluginManagementService) throws IOException { 45 | log.info("Starting plugin managing server on port " + pluginServerMgrPort); 46 | return NettyServerBuilder.forAddress( 47 | new InetSocketAddress( 48 | StrUtil.isEmpty(managementHost) ? InetAddress.getLoopbackAddress() : InetAddress.getByName(managementHost), 49 | Integer.parseInt(pluginServerMgrPort) 50 | ) 51 | ).addService(pluginManagementService) 52 | .build() 53 | .start(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: antchain-bridge-pluginserver 4 | 5 | logging: 6 | file: 7 | path: ./logs 8 | 9 | # here to configure grpc settings for the plugin server 10 | grpc: 11 | server: 12 | address: 0.0.0.0 13 | port: 9090 14 | security: 15 | # enable tls mode 16 | enabled: true 17 | # server certificate 18 | certificate-chain: file:certs/server.crt 19 | # server key 20 | private-key: file:certs/server.key 21 | # Mutual Certificate Authentication 22 | trustCertCollection: file:certs/trust.crt 23 | clientAuth: REQUIRE 24 | 25 | # settings about plugin-server 26 | pluginserver: 27 | plugin: 28 | # where to load the hetero-chain plugins 29 | repo: ./plugins 30 | policy: 31 | # limit actions of the plugin classloader 32 | classloader: 33 | resource: 34 | ban-with-prefix: 35 | # the plugin classloader will not read the resource file starting with the prefix below 36 | APPLICATION: "META-INF/services/io.grpc." 37 | managerserver: 38 | host: localhost 39 | port: 9091 -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BLUE}${AnsiStyle.BOLD} 2 | ___ __ ______ __ _ ____ _ __ 3 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 4 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 5 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 6 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 7 | /____/ 8 | plugin-server @project.version@ 9 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ${logging.path}/${APP_NAME}/error.log 16 | 17 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - 18 | %msg%n 19 | 20 | UTF-8 21 | 22 | 23 | ${logging.path}/${APP_NAME}/error.log.%d{yyyy-MM-dd}.%i 24 | 7 25 | 100MB 26 | 2GB 27 | 28 | 29 | ERROR 30 | ACCEPT 31 | DENY 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 512 39 | 40 | 41 | 42 | 43 | 44 | 45 | ${logging.path}/${APP_NAME}/application.log 46 | 47 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - 48 | %msg%n 49 | 50 | UTF-8 51 | 52 | 53 | ${logging.path}/${APP_NAME}/application.log.%d{yyyy-MM-dd}.%i 54 | 7 55 | 50MB 56 | 2GB 57 | true 58 | 59 | 60 | ERROR 61 | DENY 62 | ACCEPT 63 | 64 | 65 | 66 | 67 | 0 68 | 69 | 512 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} 80 | 81 | 82 | 83 | INFO 84 | 85 | 86 | 87 | 88 | 89 | ${logging.path}/${APP_NAME}/req_trace.log 90 | 91 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - 92 | %msg%n 93 | 94 | UTF-8 95 | 96 | 97 | ${logging.path}/${APP_NAME}/req_trace.log.%d{yyyy-MM-dd}.%i 98 | 7 99 | 50MB 100 | 500MB 101 | true 102 | 103 | 104 | 105 | 106 | 0 107 | 108 | 256 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/scripts/init_tls_certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright 2023 Ant Group 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | CURR_DIR="$(cd `dirname $0`; pwd)" 20 | source ${CURR_DIR}/print.sh 21 | 22 | print_title 23 | 24 | if [ ! -d ${CURR_DIR}/../certs ]; then 25 | mkdir -p ${CURR_DIR}/../certs 26 | fi 27 | 28 | openssl genrsa -out ${CURR_DIR}/../certs/server.key 2048 > /dev/null 2>&1 29 | if [ $? -ne 0 ]; then 30 | log_error "failed to generate server.key" 31 | exit 1 32 | fi 33 | openssl pkcs8 -topk8 -inform pem -in ${CURR_DIR}/../certs/server.key -nocrypt -out ${CURR_DIR}/../certs/server_pkcs8.key 34 | if [ $? -ne 0 ]; then 35 | log_error "failed to generate pkcs8 server.key" 36 | exit 1 37 | fi 38 | mv ${CURR_DIR}/../certs/server_pkcs8.key ${CURR_DIR}/../certs/server.key 39 | log_info "generate server.key successfully" 40 | 41 | openssl req -new -x509 -days 36500 -key ${CURR_DIR}/../certs/server.key -out ${CURR_DIR}/../certs/server.crt -subj "/C=CN/ST=mykey/L=mykey/O=mykey/OU=mykey/CN=pluginserver" 42 | if [ $? -ne 0 ]; then 43 | log_error "failed to generate server.crt" 44 | exit 1 45 | fi 46 | log_info "generate server.crt successfully" 47 | 48 | if [ ! -f "trust.crt" ]; then 49 | cp ${CURR_DIR}/../certs/server.crt ${CURR_DIR}/../certs/trust.crt 50 | log_info "generate trust.crt successfully" 51 | fi -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/scripts/plugin-server.service: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Ant Group 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | [Unit] 18 | Description=start shell script 19 | StartLimitIntervalSec=0 20 | 21 | [Service] 22 | ExecStart=@@START_CMD@@ 23 | Restart=always 24 | RestartSec=5 25 | WorkingDirectory=@@WORKING_DIR@@ 26 | 27 | [Install] 28 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/scripts/print.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Ant Group 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | RED='\033[0;31m' 18 | GREEN='\033[0;32m' 19 | BLUE='\033[0;34m' 20 | YELLOW='\033[1;33m' 21 | WHITE='\033[1;37m' 22 | NC='\033[0m' 23 | LIGHT_GRAY='\033[0;37m' 24 | 25 | function print_blue() { 26 | printf "${BLUE}%s${NC}\n" "$1" 27 | } 28 | 29 | function print_red() { 30 | printf "${RED}%s${NC}\n" "$1" 31 | } 32 | 33 | function print_green() { 34 | printf "${GREEN}%s${NC}\n" "$1" 35 | } 36 | 37 | function print_hint() { 38 | printf "${WHITE}\033[4m%s${NC}" "$1" 39 | } 40 | 41 | function log_info() { 42 | NOW=$(date "+%Y-%m-%d %H:%M:%S.%s" | cut -b 1-23) 43 | INFO_PREFIX=$(printf "${GREEN}\033[4m[ INFO ]${NC}") 44 | 45 | INFO=$(printf "_${LIGHT_GRAY}[ %s ]${NC} : %s" "${NOW}" "$1") 46 | echo "${INFO_PREFIX}${INFO}" 47 | } 48 | 49 | function log_warn() { 50 | NOW=$(date "+%Y-%m-%d %H:%M:%S.%s" | cut -b 1-23) 51 | WARN_PREFIX=$(printf "${YELLOW}\033[4m[ WARN ]${NC}") 52 | 53 | INFO=$(printf "_${LIGHT_GRAY}[ %s ]${NC} : %s" "${NOW}" "$1") 54 | echo "${WARN_PREFIX}${INFO}" 55 | } 56 | 57 | function log_error() { 58 | NOW=$(date "+%Y-%m-%d %H:%M:%S.%s" | cut -b 1-23) 59 | ERROR_PREFIX=$(printf "${RED}\033[4m[ ERROR ]${NC}") 60 | 61 | INFO=$(printf "_${LIGHT_GRAY}[ %s ]${NC} : %s" "${NOW}" "$1") 62 | echo "${ERROR_PREFIX}${INFO}" 63 | } 64 | 65 | function print_title() { 66 | echo ' ___ __ ______ __ _ ____ _ __' 67 | echo ' / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___' 68 | echo ' / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \' 69 | echo ' / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/' 70 | echo '/_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/' 71 | echo ' /____/ ' 72 | echo 73 | } 74 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright 2023 Ant Group 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | Help=$( 20 | cat <<-"HELP" 21 | 22 | start.sh — Start the plugin server 23 | 24 | Usage: 25 | start.sh 26 | 27 | Examples: 28 | 1. start in system service mode: 29 | start.sh -s 30 | 2. start in application mode: 31 | start.sh 32 | 33 | Options: 34 | -s run in system service mode. 35 | -h print help information. 36 | 37 | HELP 38 | ) 39 | 40 | CURR_DIR="$( 41 | cd $(dirname $0) 42 | pwd 43 | )" 44 | 45 | while getopts "hs" opt; do 46 | case "$opt" in 47 | "h") 48 | echo "$Help" 49 | exit 0 50 | ;; 51 | "s") 52 | IF_SYS_MODE="on" 53 | ;; 54 | "?") 55 | echo "invalid arguments. " 56 | exit 1 57 | ;; 58 | *) 59 | echo "Unknown error while processing options" 60 | exit 1 61 | ;; 62 | esac 63 | done 64 | 65 | source ${CURR_DIR}/print.sh 66 | 67 | print_title 68 | 69 | JAR_FILE=$(ls ${CURR_DIR}/../lib/ | grep '.jar') 70 | 71 | if [ "$IF_SYS_MODE" == "on" ]; then 72 | if [[ "$OSTYPE" == "darwin"* ]]; then 73 | log_error "${OSTYPE} not support running in system service mode" 74 | exit 1 75 | fi 76 | 77 | touch /usr/lib/systemd/system/test123 >/dev/null && rm -f /usr/lib/systemd/system/test123 78 | if [ $? -ne 0 ]; then 79 | log_error "Your account on this OS must have authority to access /usr/lib/systemd/system/" 80 | exit 1 81 | fi 82 | 83 | log_info "running in system service mode" 84 | 85 | JAVA_BIN=$(which java) 86 | if [ -z "$JAVA_BIN" ]; then 87 | log_error "install jdk before start" 88 | exit 1 89 | fi 90 | START_CMD="${JAVA_BIN} -jar -Dlogging.file.path=${CURR_DIR}/../log ${CURR_DIR}/../lib/${JAR_FILE} --spring.config.location=file:${CURR_DIR}/../config/application.yml" 91 | WORK_DIR="$( 92 | cd ${CURR_DIR}/.. 93 | pwd 94 | )" 95 | 96 | sed -i -e "s#@@START_CMD@@#${START_CMD}#g" ${CURR_DIR}/plugin-server.service 97 | sed -i -e "s#@@WORKING_DIR@@#${WORK_DIR}#g" ${CURR_DIR}/plugin-server.service 98 | 99 | cp -f ${CURR_DIR}/plugin-server.service /usr/lib/systemd/system/ 100 | if [ $? -ne 0 ]; then 101 | log_error "failed to cp plugin-server.service to /usr/lib/systemd/system/" 102 | exit 1 103 | fi 104 | 105 | systemctl daemon-reload && systemctl enable plugin-server.service 106 | if [ $? -ne 0 ]; then 107 | log_error "failed to enable plugin-server.service" 108 | exit 1 109 | fi 110 | 111 | systemctl start plugin-server 112 | if [ $? -ne 0 ]; then 113 | log_error "failed to start plugin-server.service" 114 | exit 1 115 | fi 116 | 117 | else 118 | log_info "running in app mode" 119 | log_info "start plugin-server now..." 120 | 121 | cd ${CURR_DIR}/.. 122 | java -jar -Dlogging.file.path=${CURR_DIR}/../log ${CURR_DIR}/../lib/${JAR_FILE} --spring.config.location=file:${CURR_DIR}/../config/application.yml >/dev/null 2>&1 & 123 | if [ $? -ne 0 ]; then 124 | log_error "failed to start plugin-server" 125 | exit 1 126 | fi 127 | fi 128 | 129 | log_info "plugin-server started successfully" 130 | -------------------------------------------------------------------------------- /ps-bootstrap/src/main/resources/scripts/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright 2023 Ant Group 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | CURR_DIR="$( 20 | cd $(dirname $0) 21 | pwd 22 | )" 23 | source ${CURR_DIR}/print.sh 24 | 25 | print_title 26 | 27 | log_info "stop plugin-server now..." 28 | 29 | ps -ewf | grep -e "ps-bootstrap.*\.jar" | grep -v grep | awk '{print $2}' | xargs kill 30 | if [ $? -ne 0 ]; then 31 | log_error "failed to stop plugin-server" 32 | exit 1 33 | fi 34 | 35 | log_info "plugin-server stopped successfully" 36 | -------------------------------------------------------------------------------- /ps-bootstrap/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: antchain-bridge-pluginserver 4 | profiles: 5 | active: dev 6 | 7 | logging: 8 | file: 9 | path: ./logs 10 | 11 | grpc: 12 | server: 13 | address: 0.0.0.0 14 | port: 9090 15 | security: 16 | # enable tls mode 17 | enabled: true 18 | # server certificate 19 | certificate-chain: classpath:server.crt 20 | # server key 21 | private-key: classpath:server.key 22 | # Mutual Certificate Authentication 23 | trustCertCollection: classpath:server.crt 24 | clientAuth: REQUIRE 25 | 26 | pluginserver: 27 | plugin: 28 | repo: src/test/resources/defaultPlugins 29 | policy: 30 | classloader: 31 | resource: 32 | ban-with-prefix: 33 | APPLICATION: "META-INF/services/io.grpc." 34 | managerserver: 35 | host: 0.0.0.0 36 | port: 9091 -------------------------------------------------------------------------------- /ps-bootstrap/src/test/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ${logging.path}/${APP_NAME}/error.log 16 | 17 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - 18 | %msg%n 19 | 20 | UTF-8 21 | 22 | 23 | ${logging.path}/${APP_NAME}/error.log.%d{yyyy-MM-dd}.%i 24 | 7 25 | 100MB 26 | 2GB 27 | 28 | 29 | ERROR 30 | ACCEPT 31 | DENY 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 512 39 | 40 | 41 | 42 | 43 | 44 | 45 | ${logging.path}/${APP_NAME}/application.log 46 | 47 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - 48 | %msg%n 49 | 50 | UTF-8 51 | 52 | 53 | ${logging.path}/${APP_NAME}/application.log.%d{yyyy-MM-dd}.%i 54 | 7 55 | 50MB 56 | 2GB 57 | true 58 | 59 | 60 | ERROR 61 | DENY 62 | ACCEPT 63 | 64 | 65 | 66 | 67 | 0 68 | 69 | 512 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} 80 | 81 | 82 | 83 | INFO 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ps-cli/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /ps-cli/README.md: -------------------------------------------------------------------------------- 1 |
2 | am logo 3 |

AntChain Bridge Plugin Server CLI

4 |
5 | 6 | ## 介绍 7 | 8 | 为了帮助管理插件服务,我们提供一个命令行工具(Command-Line Interface, CLI),帮助进行一些插件服务的运维和管理工作,比如更新插件的之后,可以通过CLI重新加载插件。 9 | 10 | ## 快速开始 11 | 12 | ### 编译 13 | 14 | 在编译插件服务的时候,会同时编译CLI。在插件服务项目的根目录下,执行: 15 | 16 | ``` 17 | mvn clean package 18 | ``` 19 | 20 | 编译之后,压缩包在路径`ps-cli/target/`之下。 21 | 22 | 当然,也可以在[release](https://github.com/AntChainOpenLab/AntChainBridgePluginServer/releases)页面下载安装包。 23 | 24 | ### 运行 25 | 26 | 首先,解压安装包,这里以`plugin-server-cli-0.2.0.tar.gz`为例。 27 | 28 | ``` 29 | tar -zxf plugin-server-cli-0.2.0.tar.gz 30 | ``` 31 | 32 | 然后,进入文件夹`plugin-server-cli`,文件结构如下: 33 | 34 | ``` 35 | . 36 | ├── README.md 37 | ├── bin 38 | │   └── start.sh 39 | └── lib 40 | └── ps-cli-0.2.0.jar 41 | 42 | 2 directories, 3 files 43 | ``` 44 | 45 | 通过运行`bin/start.sh -h`可以打印帮助信息,查看脚本使用方式: 46 | 47 | ``` 48 | ╰─± bin/start.sh -h 49 | 50 | start.sh — Start the CLI tool to manage your plugin server 51 | 52 | Usage: 53 | start.sh 54 | 55 | Examples: 56 | 1. print help info: 57 | start.sh -h 58 | 2. identify the port number to start CLI 59 | start.sh -p 9091 60 | 3. identify the server IP to start CLI 61 | start.sh -H 0.0.0.0 62 | 63 | Options: 64 | -h print help info 65 | -p identify the port number to start CLI, default 9091 66 | -H identify the server IP to start CLI, default 0.0.0.0 67 | 68 | ``` 69 | 70 | 运行`bin/start.sh`以启动CLI,按下Tab键可以补全命令。 71 | 72 | ### 使用 73 | 74 | #### 重新加载插件 75 | 76 | 场景:让插件服务,重新加载某个类型的插件。如果你修改了插件逻辑并重新编译,将插件的Jar包拷贝并覆盖原有文件,运行命令,插件服务会重新加载新的插件文件。 77 | 78 | 命令:`manage.reloadPlugin(String product)` 79 | 80 | 参数:参数`product`为插件中设置的区块链类型,比如我们提供的插件[demo](https://github.com/AntChainOpenLab/AntChainBridgePluginSDK/blob/df28f973a6f0ebdf204b86c2e49aa1be8f8d0c0c/pluginset/ethereum/offchain-plugin/src/main/java/com/alipay/antchain/bridge/plugins/ethereum/EthereumBBCService.java#L57)中的`simple-ethereum`。 81 | 82 | ``` 83 | ___ __ ______ __ _ ____ _ __ 84 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 85 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 86 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 87 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 88 | /____/ 89 | PLUGIN SERVER CLI 0.2.0 90 | 91 | >>> type help to see all commands... 92 | ps> 93 | ps> manage.reloadPlugin("simple-ethereum") 94 | ``` 95 | 96 | #### 在新路径重新加载插件 97 | 98 | 场景:让插件服务,在一个新路径重新加载某个类型的插件。如果你修改了插件逻辑并重新编译,指定新的插件文件路径,运行命令,插件服务会重新加载新的插件文件。 99 | 100 | 命令:`manage.reloadPluginInNewPath(String product, String path)` 101 | 102 | 参数:参数`product`为插件中设置的区块链类型;参数`path`指定新的插件文件路径; 103 | 104 | ``` 105 | ___ __ ______ __ _ ____ _ __ 106 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 107 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 108 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 109 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 110 | /____/ 111 | PLUGIN SERVER CLI 0.2.0 112 | 113 | >>> type help to see all commands... 114 | ps> 115 | ps> manage.reloadPluginInNewPath("simple-ethereum", "path/to/new/simple-ethereum-bbc-0.1-SNAPSHOT-plugin.jar") 116 | ``` 117 | 118 | #### 重启BBC实例 119 | 120 | 场景:当中继请求插件服务为某条链启动BBC实例之后,插件服务会从插件中读取相关Class,创建BBC实例,而更新了插件代码,经过插件的reload之后,需要重启BBC实例,才可以使用更新之后的代码提供服务。 121 | 122 | 命令:`manage.restartBBC(String product, String domain)` 123 | 124 | 参数:参数`product`为插件中设置的区块链类型;参数`domain`是你想让插件服务重新创建的BBC实例; 125 | 126 | ``` 127 | ___ __ ______ __ _ ____ _ __ 128 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 129 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 130 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 131 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 132 | /____/ 133 | PLUGIN SERVER CLI 0.2.0 134 | 135 | >>> type help to see all commands... 136 | ps> 137 | ps> manage.restartBBC("simple-ethereum", "domainA.eth.org") 138 | success 139 | ``` 140 | 141 | #### 加载新插件 142 | 143 | 场景:让插件服务,加载一个新插件,插件的类型和ID必须没有被加载过。 144 | 145 | 命令:`manage.loadPlugin(String path)` 146 | 147 | 参数:参数`path`指定新的插件文件路径,路径是相对插件服务进程的,相对路径和绝对路径都会被判断为相等; 148 | 149 | ``` 150 | ___ __ ______ __ _ ____ _ __ 151 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 152 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 153 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 154 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 155 | /____/ 156 | PLUGIN SERVER CLI 0.2.0 157 | 158 | >>> type help to see all commands... 159 | ps> 160 | ps> manage.loadPlugin("path/to/simple-ethereum-bbc-0.1-SNAPSHOT-plugin.jar") 161 | ``` 162 | 163 | #### 启动新插件 164 | 165 | 场景:让插件服务,启动一个新加载的插件(重新加载的不需要),**只有启动之后的插件才可以用于创建BBC对象**。 166 | 167 | 命令:`manage.startPlugin(String path)` 168 | 169 | 参数:参数`path`指定该插件文件路径,路径是相对插件服务进程的,相对路径和绝对路径都会被判断为相等; 170 | 171 | ``` 172 | ___ __ ______ __ _ ____ _ __ 173 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 174 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 175 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 176 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 177 | /____/ 178 | PLUGIN SERVER CLI 0.2.0 179 | 180 | >>> type help to see all commands... 181 | ps> 182 | ps> manage.startPlugin("path/to/simple-ethereum-bbc-0.1-SNAPSHOT-plugin.jar") 183 | ``` 184 | 185 | #### 停止插件 186 | 187 | 场景:让插件服务,停止使用某个插件,只有启动之后的插件才可以停止。 188 | 189 | 命令:`manage.stopPlugin(String product)` 190 | 191 | 参数:参数`product`为插件中设置的区块链类型; 192 | 193 | ``` 194 | ___ __ ______ __ _ ____ _ __ 195 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 196 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 197 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 198 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 199 | /____/ 200 | PLUGIN SERVER CLI 0.2.0 201 | 202 | >>> type help to see all commands... 203 | ps> 204 | ps> manage.stopPlugin("simple-ethereum") 205 | ``` 206 | 207 | #### 启动已停止的插件 208 | 209 | 场景:让插件服务重新启动某个已经停止的插件,只有停止之后的插件才可以重新启动。 210 | 211 | 命令:`manage.startPluginFromStop(String product)` 212 | 213 | 参数:参数`product`为插件中设置的区块链类型; 214 | 215 | ``` 216 | ___ __ ______ __ _ ____ _ __ 217 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 218 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 219 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 220 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 221 | /____/ 222 | PLUGIN SERVER CLI 0.2.0 223 | 224 | >>> type help to see all commands... 225 | ps> 226 | ps> manage.startPluginFromStop("simple-ethereum") 227 | ``` 228 | 229 | #### 查询当前所有已启动插件的类型列表 230 | 231 | 场景:让插件服务返回当前所有已经启动的插件类型列表。 232 | 233 | 命令:`manage.allPlugins()` 234 | 235 | ``` 236 | ___ __ ______ __ _ ____ _ __ 237 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 238 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 239 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 240 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 241 | /____/ 242 | PLUGIN SERVER CLI 0.2.0 243 | 244 | >>> type help to see all commands... 245 | ps> manage.allPlugins() 246 | simple-ethereum, testchain 247 | ``` 248 | 249 | #### 查询当前所有服务中的区块链域名列表 250 | 251 | 场景:让插件服务返回当前所有服务中的区块链域名列表 252 | 253 | 命令:` manage.allDomains()` 254 | 255 | ``` 256 | ___ __ ______ __ _ ____ _ __ 257 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 258 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 259 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 260 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 261 | /____/ 262 | PLUGIN SERVER CLI 0.2.0 263 | 264 | >>> type help to see all commands... 265 | ps> manage.allDomains() 266 | chaina, chainb 267 | ``` 268 | 269 | #### 查询某些区块链是否有启动的插件 270 | 271 | 场景:查询插件服务某些指定的区块链类型是否有已经启动的插件。 272 | 273 | 命令:` manage.hasPlugins(String[] products...)` 274 | 275 | 参数:`products`是区块链插件类型的数组; 276 | 277 | ``` 278 | ___ __ ______ __ _ ____ _ __ 279 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 280 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 281 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 282 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 283 | /____/ 284 | PLUGIN SERVER CLI 0.2.0 285 | 286 | >>> type help to see all commands... 287 | ps> manage.hasPlugins("simple-ethereum", "testchain", "notexist") 288 | { 289 | "testchain":true, 290 | "notexist":false, # false 代表不存在 291 | "simple-ethereum":true # true 代表存在 292 | } 293 | ``` 294 | 295 | #### 查询某些域名是否正在服务 296 | 297 | 场景:查询插件服务某些域名是否正在服务,即有正在运行的区块链BBC对象。 298 | 299 | 命令:` manage.hasDomains(String[] domains...)` 300 | 301 | 参数:`domains`是区块链插件类型的数组; 302 | 303 | ``` 304 | ___ __ ______ __ _ ____ _ __ 305 | / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___ 306 | / /| | / __ \ / __// / / __ \ / __ `// // __ \ / __ |/ ___// // __ // __ `// _ \ 307 | / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/ 308 | /_/ |_|/_/ /_/ \__/ \____//_/ /_/ \__,_//_//_/ /_/ /_____//_/ /_/ \__,_/ \__, / \___/ 309 | /____/ 310 | PLUGIN SERVER CLI 0.2.0 311 | 312 | >>> type help to see all commands... 313 | ps> manage.hasDomains("chaina", "chainb") 314 | { 315 | "chainb":true, 316 | "chaina":false 317 | } 318 | ``` 319 | 320 | -------------------------------------------------------------------------------- /ps-cli/desc_tar.xml: -------------------------------------------------------------------------------- 1 | 4 | ${version} 5 | 6 | tar.gz 7 | 8 | true 9 | 10 | 11 | ${project.basedir}/target/boot/ 12 | ${file.separator}lib 13 | 14 | ${artifactId}-${version}.jar 15 | 16 | 17 | 18 | ${project.basedir}/src/main/resources/scripts 19 | ${file.separator}bin 20 | 21 | *.sh 22 | 23 | 24 | 25 | ${project.basedir}/ 26 | ${file.separator} 27 | 28 | README.md 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ps-cli/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alipay.antchain.bridge 8 | antchain-bridge-pluginserver 9 | 0.2.3 10 | 11 | 12 | ps-cli 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | com.alipay.antchain.bridge 23 | ps-service 24 | 25 | 26 | org.jline 27 | jline 28 | 29 | 30 | org.codehaus.groovy 31 | groovy-all 32 | pom 33 | 34 | 35 | commons-cli 36 | commons-cli 37 | 38 | 39 | cn.hutool 40 | hutool-all 41 | 42 | 43 | io.grpc 44 | grpc-netty-shaded 45 | 46 | 47 | com.alibaba 48 | fastjson 49 | 50 | 51 | 52 | 53 | 54 | 55 | src/main/resources 56 | 57 | **/*.xml 58 | **/VERSION 59 | 60 | 61 | true 62 | 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-maven-plugin 68 | 69 | 70 | 71 | org.projectlombok 72 | lombok 73 | 74 | 75 | ./target/boot 76 | 77 | 78 | 79 | 80 | repackage 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-assembly-plugin 88 | 3.1.0 89 | 90 | 91 | 92 | plugin-server-cli 93 | 94 | desc_tar.xml 95 | 96 | 97 | make-tar 98 | package 99 | 100 | single 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/ArgsConstraint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | import java.lang.annotation.Target; 23 | 24 | @Target(ElementType.PARAMETER) 25 | @Retention(RetentionPolicy.RUNTIME) 26 | public @interface ArgsConstraint { 27 | 28 | String name() default ""; 29 | 30 | String[] constraints() default ""; 31 | } 32 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/Command.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class Command { 23 | 24 | /** 25 | * 命令名称 26 | */ 27 | private String name; 28 | 29 | /** 30 | * 命令参数描述 31 | */ 32 | private List args = new ArrayList<>(); 33 | 34 | /** 35 | * 使用命令名称构造命令 36 | * 37 | * @param name 38 | */ 39 | public Command(String name) { 40 | this.name = name; 41 | } 42 | 43 | /** 44 | * 添加参数 45 | * 46 | * @param argName 参数名称 47 | * @param constraints 参数取值约束 48 | */ 49 | public void addArgs(String argName, String type, List constraints) { 50 | 51 | Arg item = new Arg(); 52 | item.name = argName; 53 | item.type = type; 54 | item.constraints = constraints; 55 | 56 | this.args.add(item); 57 | } 58 | 59 | /** 60 | * Getter method for property name.. 61 | * 62 | * @return property value of name. 63 | */ 64 | public String getName() { 65 | return name; 66 | } 67 | 68 | /** 69 | * Getter method for property args.. 70 | * 71 | * @return property value of args. 72 | */ 73 | public List getArgs() { 74 | return args; 75 | } 76 | 77 | /** 78 | * 参数描述类 79 | */ 80 | public static class Arg { 81 | private String name; 82 | private String type; 83 | private List constraints; 84 | 85 | /** 86 | * Getter method for property name.. 87 | * 88 | * @return property value of name. 89 | */ 90 | public String getName() { 91 | return name; 92 | } 93 | 94 | /** 95 | * Getter method for property constraints.. 96 | * 97 | * @return property value of constraints. 98 | */ 99 | public List getConstraints() { 100 | return constraints; 101 | } 102 | 103 | /** 104 | * Getter method for property type.. 105 | * 106 | * @return property value of type. 107 | */ 108 | public String getType() { 109 | return type; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/CommandHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | @FunctionalInterface 20 | public interface CommandHandler { 21 | 22 | /** 23 | * 执行命令 24 | * 25 | * @param namespace 命令空间 26 | * @param command 命令 27 | * @param params 执行参数 28 | * @return 29 | */ 30 | Object execute(String namespace, String command, String... params); 31 | } 32 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/CommandNamespace.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.util.Map; 20 | 21 | /** 22 | * 命令命名空间 23 | */ 24 | public interface CommandNamespace { 25 | 26 | /** 27 | * 命名空间名称 28 | * 29 | * @return 30 | */ 31 | public String name(); 32 | 33 | /** 34 | * 获取命令命名空间下所有命令 35 | * 36 | * @return 37 | */ 38 | public Map getCommands(); 39 | } 40 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/CommandNamespaceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | public class CommandNamespaceImpl implements CommandNamespace { 23 | /** 24 | * 命令集合 25 | */ 26 | private final Map commands = new HashMap<>(); 27 | 28 | /** 29 | * 命名空间名称 30 | * 31 | * @return 32 | */ 33 | @Override 34 | public String name() { 35 | return null; 36 | } 37 | 38 | /** 39 | * 往命名空间添加一个命令 40 | * 41 | * @param cmd 42 | */ 43 | public void addCommand(Command cmd) { 44 | commands.put(cmd.getName(), cmd); 45 | } 46 | 47 | /** 48 | * 获取命名空间下所有命令 49 | * 50 | * @return 51 | */ 52 | public Map getCommands() { 53 | return commands; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/ManagementCommandNamespace.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import com.alipay.antchain.bridge.pluginserver.cli.shell.GroovyScriptCommandNamespace; 20 | 21 | public class ManagementCommandNamespace extends GroovyScriptCommandNamespace { 22 | @Override 23 | public String name() { 24 | return "manage"; 25 | } 26 | 27 | Object loadPlugins() { 28 | return queryAPI("loadPlugins"); 29 | } 30 | 31 | Object startPlugins() { 32 | return queryAPI("startPlugins"); 33 | } 34 | 35 | Object loadPlugin( 36 | @ArgsConstraint(name = "path") String path 37 | ) { 38 | return queryAPI("loadPlugin", path); 39 | } 40 | 41 | Object startPlugin( 42 | @ArgsConstraint(name = "path") String path 43 | ) { 44 | return queryAPI("startPlugin", path); 45 | } 46 | 47 | Object stopPlugin( 48 | @ArgsConstraint(name = "product") String product 49 | ) { 50 | return queryAPI("stopPlugin", product); 51 | } 52 | 53 | Object startPluginFromStop( 54 | @ArgsConstraint(name = "product") String product 55 | ) { 56 | return queryAPI("startPluginFromStop", product); 57 | } 58 | 59 | Object reloadPlugin( 60 | @ArgsConstraint(name = "product") String product 61 | ) { 62 | return queryAPI("reloadPlugin", product); 63 | } 64 | 65 | Object reloadPluginInNewPath( 66 | @ArgsConstraint(name = "product") String product, 67 | @ArgsConstraint(name = "path") String path 68 | ) { 69 | return queryAPI("reloadPluginInNewPath", product, path); 70 | } 71 | 72 | Object hasPlugins( 73 | @ArgsConstraint(name = "products...") String... products 74 | ) { 75 | return queryAPI("hasPlugins", products); 76 | } 77 | 78 | Object allPlugins() { 79 | return queryAPI("allPlugins"); 80 | } 81 | 82 | Object hasDomains( 83 | @ArgsConstraint(name = "domains...") String... domains 84 | ) { 85 | return queryAPI("hasDomains", domains); 86 | } 87 | 88 | Object allDomains() { 89 | return queryAPI("allDomains"); 90 | } 91 | 92 | Object restartBBC( 93 | @ArgsConstraint(name = "product") String product, 94 | @ArgsConstraint(name = "domain") String domain 95 | ) { 96 | return queryAPI("restartBBC", product, domain); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/NamespaceManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.util.List; 20 | 21 | public interface NamespaceManager { 22 | 23 | /** 24 | * 添加namespace 25 | * 26 | * @param commandNamespace 27 | */ 28 | void addNamespace(CommandNamespace commandNamespace); 29 | 30 | /** 31 | * 获取所有namespace 32 | * 33 | * @return 34 | */ 35 | List getCommandNamespaces(); 36 | 37 | /** 38 | * namespace快照 39 | * 40 | * @return 41 | */ 42 | String dump(); 43 | } 44 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/command/NamespaceManagerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.command; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class NamespaceManagerImpl implements NamespaceManager { 23 | 24 | private final List commandNamespaces = new ArrayList<>(); 25 | 26 | public NamespaceManagerImpl() { 27 | addNamespace(new ManagementCommandNamespace()); 28 | } 29 | 30 | @Override 31 | public void addNamespace(CommandNamespace commandNamespace) { 32 | this.commandNamespaces.add(commandNamespace); 33 | } 34 | 35 | @Override 36 | public List getCommandNamespaces() { 37 | return commandNamespaces; 38 | } 39 | 40 | @Override 41 | public String dump() { 42 | StringBuilder builder = new StringBuilder(); 43 | commandNamespaces.forEach( 44 | commandNamespace -> { 45 | builder.append("\n").append(commandNamespace.name()); 46 | commandNamespace.getCommands().forEach( 47 | (cmdName, cmd) -> { 48 | builder.append("\n\t.").append(cmdName); 49 | if (!cmd.getArgs().isEmpty()) { 50 | builder.append("("); 51 | cmd.getArgs().forEach( 52 | arg -> { 53 | builder.append(arg.getName()).append(","); 54 | } 55 | ); 56 | builder.deleteCharAt(builder.length() - 1); 57 | builder.append(")"); 58 | } else { 59 | builder.append("()"); 60 | } 61 | } 62 | ); 63 | } 64 | ); 65 | 66 | return builder.append("\n\n").toString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/core/ManagementGrpcClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.core; 18 | 19 | import java.io.IOException; 20 | import java.net.Socket; 21 | import java.util.List; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | import cn.hutool.core.collection.CollUtil; 25 | import com.alibaba.fastjson.JSON; 26 | import com.alipay.antchain.bridge.pluginserver.managementservice.*; 27 | import io.grpc.ManagedChannel; 28 | import io.grpc.ManagedChannelBuilder; 29 | 30 | public class ManagementGrpcClient { 31 | 32 | private final ManagedChannel channel; 33 | private ManagementServiceGrpc.ManagementServiceBlockingStub blockingStub; 34 | 35 | private final String host; 36 | 37 | private final int port; 38 | 39 | public ManagementGrpcClient(int port) { 40 | this("127.0.0.1", port); 41 | } 42 | 43 | public ManagementGrpcClient(String host, int port) { 44 | this.port = port; 45 | this.host = host; 46 | this.channel = ManagedChannelBuilder.forAddress(this.host, this.port) 47 | .usePlaintext() 48 | .build(); 49 | this.blockingStub = ManagementServiceGrpc.newBlockingStub(channel); 50 | } 51 | 52 | public boolean checkServerStatus() { 53 | try { 54 | Socket socket = new Socket(host, port); 55 | socket.close(); 56 | return true; 57 | } catch (IOException e) { 58 | return false; 59 | } 60 | } 61 | 62 | public void shutdown() throws InterruptedException { 63 | channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); 64 | } 65 | 66 | public String managePlugin(PluginManageRequest.Type type, String product, String path) { 67 | ManageResponse response = this.blockingStub.managePlugin( 68 | PluginManageRequest.newBuilder() 69 | .setType(type) 70 | .setPath(path) 71 | .setProduct(product) 72 | .build() 73 | ); 74 | return response.getCode() == 0 ? "success" : "failed with msg: " + response.getErrorMsg(); 75 | } 76 | 77 | public String hasPlugins(List productList) { 78 | ManageResponse response = this.blockingStub.hasPlugins( 79 | HasPluginsRequest.newBuilder() 80 | .addAllProducts(productList) 81 | .build() 82 | ); 83 | if (response.getCode() != 0) { 84 | return "failed with msg: " + response.getErrorMsg(); 85 | } 86 | 87 | return JSON.toJSONString(response.getHasPluginsResp().getResultsMap()); 88 | } 89 | 90 | public String getAllPlugins() { 91 | ManageResponse response = this.blockingStub.allPlugins(AllPluginsRequest.newBuilder().build()); 92 | if (response.getCode() != 0) { 93 | return "failed with msg: " + response.getErrorMsg(); 94 | } 95 | 96 | return CollUtil.join(response.getAllPluginsResp().getProductsList(), ", "); 97 | } 98 | 99 | public String hasDomains(List domains) { 100 | ManageResponse response = this.blockingStub.hasDomains( 101 | HasDomainsRequest.newBuilder() 102 | .addAllDomains(domains) 103 | .build() 104 | ); 105 | if (response.getCode() != 0) { 106 | return "failed with msg: " + response.getErrorMsg(); 107 | } 108 | 109 | return JSON.toJSONString(response.getHasDomainsResp().getResultsMap()); 110 | } 111 | 112 | public String getAllDomains() { 113 | ManageResponse response = this.blockingStub.allDomains(AllDomainsRequest.newBuilder().build()); 114 | if (response.getCode() != 0) { 115 | return "failed with msg: " + response.getErrorMsg(); 116 | } 117 | 118 | return CollUtil.join(response.getAllDomainsResp().getDomainsList(), ", "); 119 | } 120 | 121 | public String restartBBC(String product, String domain) { 122 | ManageResponse response = this.blockingStub.restartBBC( 123 | RestartBBCRequest.newBuilder() 124 | .setProduct(product) 125 | .setDomain(domain) 126 | .build() 127 | ); 128 | if (response.getCode() != 0) { 129 | return "failed with msg: " + response.getErrorMsg(); 130 | } 131 | return "success"; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/GroovyScriptCommandNamespace.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | import java.lang.reflect.Method; 20 | import java.lang.reflect.Parameter; 21 | import java.util.List; 22 | import java.util.stream.Stream; 23 | 24 | import cn.hutool.core.collection.ListUtil; 25 | import com.alipay.antchain.bridge.pluginserver.cli.command.ArgsConstraint; 26 | import com.alipay.antchain.bridge.pluginserver.cli.command.Command; 27 | import com.alipay.antchain.bridge.pluginserver.cli.command.CommandNamespaceImpl; 28 | import com.alipay.antchain.bridge.pluginserver.managementservice.PluginManageRequest; 29 | import com.google.common.collect.Lists; 30 | 31 | public abstract class GroovyScriptCommandNamespace extends CommandNamespaceImpl { 32 | 33 | private static final String COMMAND_NAMESPACE_NAME = "name"; 34 | 35 | /** 36 | * 命名空间名称由子类实现 37 | * 38 | * @return 39 | */ 40 | @Override 41 | public abstract String name(); 42 | 43 | public GroovyScriptCommandNamespace() { 44 | super(); 45 | loadCommand(); 46 | } 47 | 48 | /** 49 | * 初始化:加载command,默认将子类所有方法解析为命令 50 | */ 51 | public void loadCommand() { 52 | 53 | Method[] methods = this.getClass().getDeclaredMethods(); 54 | 55 | Stream.of(methods).forEach(method -> { 56 | 57 | if (COMMAND_NAMESPACE_NAME.equals(method.getName())) { 58 | return; 59 | } 60 | 61 | Command cmd = new Command(method.getName()); 62 | 63 | Parameter[] params = method.getParameters(); 64 | 65 | for (Parameter param : params) { 66 | 67 | String argName = param.getName(); 68 | List constraints = Lists.newArrayList(); 69 | 70 | ArgsConstraint argsConstraint = param.getAnnotation(ArgsConstraint.class); 71 | 72 | if (null != argsConstraint) { 73 | if (null != argsConstraint.name() && !"".equals(argsConstraint.name().trim())) { 74 | argName = argsConstraint.name().trim(); 75 | } 76 | if (null != argsConstraint.constraints()) { 77 | Stream.of(argsConstraint.constraints()).filter( 78 | constraint -> null != constraint && !"".equals(constraint.trim())).forEach( 79 | constraint -> constraints.add(constraint)); 80 | } 81 | } 82 | 83 | cmd.addArgs(argName, param.getType().getSimpleName(), constraints); 84 | } 85 | addCommand(cmd); 86 | }); 87 | } 88 | 89 | protected String queryAPI(String command, Object... args) { 90 | 91 | if (args != null) { 92 | String[] strArgs = new String[args.length]; 93 | for (int i = 0; i < args.length; ++i) { 94 | strArgs[i] = args[i].toString(); 95 | } 96 | 97 | return queryAPI(command, strArgs); 98 | } else { 99 | 100 | return queryAPI(command); 101 | } 102 | } 103 | 104 | /** 105 | * 查询api,供子类命令执行使用 106 | * 107 | * @param command 108 | * @param args 109 | * @return 110 | */ 111 | protected String queryAPI(String command, String... args) { 112 | 113 | switch (command) { 114 | case "loadPlugins": 115 | return Shell.RUNTIME.getGrpcClient().managePlugin( 116 | PluginManageRequest.Type.LOAD_PLUGINS, 117 | "", "" 118 | ); 119 | case "startPlugins": 120 | return Shell.RUNTIME.getGrpcClient().managePlugin( 121 | PluginManageRequest.Type.START_PLUGINS, 122 | "", "" 123 | ); 124 | case "reloadPlugin": 125 | if (args.length != 1) { 126 | return "wrong length of arguments"; 127 | } 128 | return Shell.RUNTIME.getGrpcClient().managePlugin( 129 | PluginManageRequest.Type.RELOAD_PLUGIN, 130 | args[0], "" 131 | ); 132 | case "reloadPluginInNewPath": 133 | if (args.length != 2) { 134 | return "wrong length of arguments"; 135 | } 136 | return Shell.RUNTIME.getGrpcClient().managePlugin( 137 | PluginManageRequest.Type.RELOAD_PLUGIN_IN_NEW_PATH, 138 | args[0], args[1] 139 | ); 140 | case "startPlugin": 141 | if (args.length != 1) { 142 | return "wrong length of arguments"; 143 | } 144 | return Shell.RUNTIME.getGrpcClient().managePlugin( 145 | PluginManageRequest.Type.START_PLUGIN, 146 | "", args[0] 147 | ); 148 | case "stopPlugin": 149 | if (args.length != 1) { 150 | return "wrong length of arguments"; 151 | } 152 | return Shell.RUNTIME.getGrpcClient().managePlugin( 153 | PluginManageRequest.Type.STOP_PLUGIN, 154 | args[0], "" 155 | ); 156 | case "loadPlugin": 157 | if (args.length != 1) { 158 | return "wrong length of arguments"; 159 | } 160 | return Shell.RUNTIME.getGrpcClient().managePlugin( 161 | PluginManageRequest.Type.LOAD_PLUGIN, 162 | "", args[0] 163 | ); 164 | case "startPluginFromStop": 165 | if (args.length != 1) { 166 | return "wrong length of arguments"; 167 | } 168 | return Shell.RUNTIME.getGrpcClient().managePlugin( 169 | PluginManageRequest.Type.START_PLUGIN_FROM_STOP, 170 | args[0], "" 171 | ); 172 | case "hasPlugins": 173 | if (args.length == 0) { 174 | return "zero arguments"; 175 | } 176 | return Shell.RUNTIME.getGrpcClient().hasPlugins(ListUtil.toList(args)); 177 | case "allPlugins": 178 | if (args.length != 0) { 179 | return "wrong length of arguments"; 180 | } 181 | return Shell.RUNTIME.getGrpcClient().getAllPlugins(); 182 | case "hasDomains": 183 | if (args.length == 0) { 184 | return "zero arguments"; 185 | } 186 | return Shell.RUNTIME.getGrpcClient().hasDomains(ListUtil.toList(args)); 187 | case "allDomains": 188 | if (args.length != 0) { 189 | return "wrong length of arguments"; 190 | } 191 | return Shell.RUNTIME.getGrpcClient().getAllDomains(); 192 | case "restartBBC": 193 | if (args.length != 2) { 194 | return "wrong length of arguments"; 195 | } 196 | return Shell.RUNTIME.getGrpcClient().restartBBC(args[0], args[1]); 197 | default: 198 | return "wrong command " + command; 199 | } 200 | } 201 | 202 | protected void print(String result) { 203 | Shell.RUNTIME.getPrinter().println(result); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/GroovyShellProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | import java.beans.Introspector; 20 | 21 | import com.alipay.antchain.bridge.pluginserver.cli.command.NamespaceManager; 22 | import groovy.lang.GroovyShell; 23 | import groovy.lang.Script; 24 | import org.codehaus.groovy.reflection.ClassInfo; 25 | import org.codehaus.groovy.runtime.InvokerHelper; 26 | 27 | public class GroovyShellProvider extends GroovyShell implements ShellProvider { 28 | 29 | private NamespaceManager namespaceManager; 30 | 31 | public GroovyShellProvider(NamespaceManager namespaceManager) { 32 | this.namespaceManager = namespaceManager; 33 | 34 | // init GroovyShell 35 | this.namespaceManager.getCommandNamespaces().forEach(namespace -> { 36 | 37 | // only load GroovyScriptCommandNamespace 38 | if (namespace instanceof GroovyScriptCommandNamespace) { 39 | this.setVariable(namespace.name(), namespace); 40 | } 41 | }); 42 | } 43 | 44 | private int cleanCount = 0; 45 | 46 | private static int CLEAN_PERIOD = 20; 47 | 48 | @Override 49 | public String execute(String cmd) { 50 | Script shell = this.parse(cmd); 51 | Object scriptObject = InvokerHelper.createScript(shell.getClass(), this.getContext()).run(); 52 | 53 | // 周期清除缓存,防止OOM 54 | if((++cleanCount) % CLEAN_PERIOD == 0) { 55 | getClassLoader().clearCache(); 56 | ClassInfo.clearModifiedExpandos(); 57 | Introspector.flushCaches(); 58 | } 59 | 60 | // execute by groovy script 61 | return scriptObject.toString(); 62 | } 63 | 64 | @Override 65 | public void shutdown() { 66 | // nothing 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/JsonUtil.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2023 Ant Group 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 19 | 20 | public class JsonUtil { 21 | /** 22 | * 得到格式化json数据 退格用\t 换行用\r 23 | */ 24 | public static String format(String jsonStr) { 25 | int level = 0; 26 | StringBuffer jsonForMatStr = new StringBuffer(); 27 | for (int i = 0; i < jsonStr.length(); i++) { 28 | char c = jsonStr.charAt(i); 29 | if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) { 30 | jsonForMatStr.append(getLevelStr(level)); 31 | } 32 | switch (c) { 33 | case '{': 34 | case '[': 35 | jsonForMatStr.append(c + "\n"); 36 | level++; 37 | break; 38 | case ',': 39 | jsonForMatStr.append(c + "\n"); 40 | break; 41 | case '}': 42 | case ']': 43 | jsonForMatStr.append("\n"); 44 | level--; 45 | jsonForMatStr.append(getLevelStr(level)); 46 | jsonForMatStr.append(c); 47 | break; 48 | default: 49 | jsonForMatStr.append(c); 50 | break; 51 | } 52 | } 53 | 54 | return jsonForMatStr.toString(); 55 | 56 | } 57 | 58 | private static String getLevelStr(int level) { 59 | StringBuffer levelStr = new StringBuffer(); 60 | for (int levelI = 0; levelI < level; levelI++) { 61 | levelStr.append("\t"); 62 | } 63 | return levelStr.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/Launcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | import java.io.*; 20 | import java.nio.charset.Charset; 21 | 22 | import cn.hutool.core.io.resource.ResourceUtil; 23 | import com.alipay.antchain.bridge.pluginserver.cli.command.NamespaceManager; 24 | import com.alipay.antchain.bridge.pluginserver.cli.command.NamespaceManagerImpl; 25 | import com.alipay.antchain.bridge.pluginserver.cli.core.ManagementGrpcClient; 26 | import org.apache.commons.cli.*; 27 | 28 | public class Launcher { 29 | private static final String OP_HELP = "h"; 30 | private static final String OP_VERSION = "v"; 31 | private static final String OP_PORT = "p"; 32 | private static final String OP_CMD = "c"; 33 | private static final String OP_FILE = "f"; 34 | 35 | private static final String OP_HOST = "H"; 36 | 37 | private static final Options options; 38 | 39 | static { 40 | options = new Options(); 41 | options.addOption(OP_HELP, "help", false, "print help info"); 42 | options.addOption(OP_VERSION, "version", false, "print version info"); 43 | options.addOption(OP_PORT, "port", true, "management server port"); 44 | options.addOption(OP_CMD, "command", true, "execute the command"); 45 | options.addOption(OP_FILE, "file", true, "execute multiple commands in the file"); 46 | options.addOption(OP_HOST, "host", true, "set the host"); 47 | } 48 | 49 | public static void main(String[] args) throws ParseException { 50 | 51 | CommandLineParser parser = new DefaultParser(); 52 | CommandLine cmd = parser.parse(options, args); 53 | 54 | if (cmd.hasOption(OP_HELP)) { 55 | HelpFormatter helpFormatter = new HelpFormatter(); 56 | helpFormatter.printHelp("plugin server CLI", options); 57 | return; 58 | } 59 | 60 | if (cmd.hasOption(OP_VERSION)) { 61 | System.out.printf("cli version : %s\n", getVersion()); 62 | return; 63 | } 64 | 65 | int port = 9091; 66 | if (cmd.hasOption(OP_PORT)) { 67 | port = Integer.parseInt(cmd.getOptionValue(OP_PORT)); 68 | } 69 | 70 | // new namespace 71 | NamespaceManager namespaceManager = new NamespaceManagerImpl(); 72 | 73 | // new shellProvider 74 | ShellProvider shellProvider = new GroovyShellProvider(namespaceManager); 75 | 76 | // new promptCompleter 77 | PromptCompleter promptCompleter = new PromptCompleter(); 78 | promptCompleter.addNamespace(namespaceManager); 79 | 80 | // new grpcClient 81 | String host = "localhost"; 82 | if (cmd.hasOption(OP_HOST)) { 83 | host = cmd.getOptionValue(OP_HOST); 84 | } 85 | ManagementGrpcClient grpcClient = new ManagementGrpcClient(host, port); 86 | 87 | if (!grpcClient.checkServerStatus()) { 88 | System.out.printf("start failed, can't connect to local server port: %d\n", port); 89 | return; 90 | } 91 | 92 | // new shell 93 | Shell shell = new Shell(shellProvider, promptCompleter, grpcClient, namespaceManager); 94 | 95 | if (cmd.hasOption(OP_CMD)) { 96 | String command = cmd.getOptionValue(OP_CMD); 97 | 98 | try { 99 | String result = shell.execute(command); 100 | System.out.println(result); 101 | } catch (Exception e) { 102 | System.out.printf("illegal command [ %s ], execute failed\n", command); 103 | } 104 | return; 105 | } 106 | 107 | if (cmd.hasOption(OP_FILE)) { 108 | String filePath = cmd.getOptionValue(OP_FILE); 109 | 110 | String command = ""; 111 | try { 112 | BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(filePath)))); 113 | 114 | command = reader.readLine(); 115 | StringBuilder resultBuilder = new StringBuilder(); 116 | while (null != command) { 117 | try { 118 | String result = shell.execute(command); 119 | resultBuilder.append(result).append("\n"); 120 | } catch (Exception e) { 121 | resultBuilder.append("error\n"); 122 | } 123 | command = reader.readLine(); 124 | } 125 | 126 | System.out.println(resultBuilder); 127 | 128 | } catch (FileNotFoundException e) { 129 | System.out.printf("error: file %s not found\n", filePath); 130 | } catch (IOException e) { 131 | System.out.println("error: io exception"); 132 | e.printStackTrace(); 133 | } catch (Exception e) { 134 | System.out.printf("illegal command [ %s ], execute failed\n", command); 135 | e.printStackTrace(); 136 | } 137 | 138 | return; 139 | } 140 | 141 | shell.start(); 142 | 143 | Runtime.getRuntime().addShutdownHook(new Thread(shell::stop)); 144 | } 145 | 146 | public static String getVersion() { 147 | return ResourceUtil.readStr("VERSION", Charset.defaultCharset()); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/PromptCompleter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import com.alipay.antchain.bridge.pluginserver.cli.command.CommandNamespace; 23 | import com.alipay.antchain.bridge.pluginserver.cli.command.NamespaceManager; 24 | import org.jline.reader.Candidate; 25 | import org.jline.reader.Completer; 26 | import org.jline.reader.LineReader; 27 | import org.jline.reader.ParsedLine; 28 | 29 | public class PromptCompleter implements Completer { 30 | 31 | private List namespaces = new ArrayList<>(); 32 | 33 | private List reservedWords = new ArrayList<>(); 34 | 35 | /** 36 | * 添加namespace 37 | * 38 | * @param namespaceManager 39 | */ 40 | public void addNamespace(NamespaceManager namespaceManager) { 41 | 42 | namespaces.addAll(namespaceManager.getCommandNamespaces()); 43 | } 44 | 45 | /** 46 | * 添加保留字 47 | * 48 | * @param reservedWord 49 | */ 50 | public void addReservedWord(String reservedWord) { 51 | this.reservedWords.add(reservedWord); 52 | } 53 | 54 | @Override 55 | public void complete(LineReader lineReader, ParsedLine commandLine, List candidates) { 56 | assert commandLine != null; 57 | assert candidates != null; 58 | 59 | String buffer = commandLine.line().substring(0, commandLine.cursor()); 60 | 61 | //如果未输入.符号,则补全保留字与命令 62 | if (!buffer.contains(".")) { 63 | 64 | // 补全保留字 65 | reservedWords.forEach(reservedWord -> { 66 | if (!buffer.isEmpty() && !reservedWord.startsWith(buffer)) { 67 | return; 68 | } 69 | 70 | candidates.add(new Candidate(reservedWord, reservedWord, null, null, null, null, true)); 71 | }); 72 | 73 | // 补全命令 74 | namespaces.forEach(namespace -> { 75 | 76 | if (!buffer.isEmpty() && !namespace.name().startsWith(buffer)) { 77 | return; 78 | } 79 | 80 | StringBuilder sb = new StringBuilder(namespace.name()); 81 | namespace.getCommands().forEach((cmdName, cmd) -> { 82 | 83 | sb.append("\n\t.").append(cmdName); 84 | if (!cmd.getArgs().isEmpty()) { 85 | sb.append("("); 86 | cmd.getArgs().forEach(arg -> { 87 | sb.append("String ").append(arg.getName()).append(","); 88 | }); 89 | sb.deleteCharAt(sb.length() - 1); 90 | sb.append(")"); 91 | 92 | } else { 93 | sb.append("()"); 94 | } 95 | }); 96 | 97 | candidates.add(new Candidate(namespace.name() + ".", namespace.name(), null, null, null, null, true)); 98 | }); 99 | } else if (buffer.contains("(")) {// 已输入完整的命令(判断是否已输入"("符号),则补全详细的参数字段 100 | 101 | String[] buf = buffer.split("\\."); 102 | 103 | namespaces.forEach(namespace -> { 104 | 105 | if (!namespace.name().equals(buf[0])) { 106 | return; 107 | } 108 | namespace.getCommands().forEach((cmdName, cmd) -> { 109 | 110 | String command = buf[1].split("\\(")[0]; 111 | 112 | if (cmdName.equals(command)) { 113 | 114 | StringBuilder sb = new StringBuilder(cmdName); 115 | if (!cmd.getArgs().isEmpty()) { 116 | sb.append("("); 117 | cmd.getArgs().forEach(arg -> { 118 | sb.append("\n ").append(arg.getType()).append(" ").append(arg.getName()).append(" "); 119 | 120 | if (!arg.getConstraints().isEmpty()) { 121 | sb.append(" //"); 122 | arg.getConstraints().forEach(contraint -> { 123 | sb.append(contraint).append(","); 124 | }); 125 | sb.deleteCharAt(sb.length() - 1); 126 | } 127 | }); 128 | sb.append("\n)"); 129 | 130 | candidates.add( 131 | new Candidate(buffer, sb.toString(), null, null, null, 132 | null, true)); 133 | } else { 134 | sb.append("()"); 135 | candidates.add( 136 | new Candidate(namespace.name() + "." + cmdName + "()", sb.toString(), null, null, null, 137 | null, true)); 138 | } 139 | } 140 | }); 141 | }); 142 | } else { //已输入.符号,则补全匹配命令 143 | String[] buf = buffer.split("\\."); 144 | 145 | namespaces.forEach(namespace -> { 146 | 147 | if (!namespace.name().equals(buf[0])) { 148 | return; 149 | } 150 | 151 | long matchCount = namespace.getCommands().keySet().stream().filter( 152 | cmdName -> cmdName.startsWith(buf.length <= 1 ? "" : buf[1])).count(); 153 | 154 | namespace.getCommands().forEach((cmdName, cmd) -> { 155 | 156 | if (cmdName.startsWith(buf.length <= 1 ? "" : buf[1])) { 157 | 158 | StringBuilder sb = new StringBuilder(cmdName); 159 | if (cmd.getArgs().isEmpty()) { 160 | sb.append("()"); 161 | candidates.add( 162 | new Candidate(namespace.name() + "." + cmdName + "()", sb.toString(), null, null, null, 163 | null, true)); 164 | 165 | } else if (matchCount == 1) { 166 | sb.append("("); 167 | cmd.getArgs().forEach(arg -> { 168 | sb.append("\n ").append(arg.getType()).append(" ").append(arg.getName()).append(" "); 169 | 170 | if (!arg.getConstraints().isEmpty()) { 171 | sb.append(" //"); 172 | arg.getConstraints().forEach(contraint -> { 173 | sb.append(contraint).append(","); 174 | }); 175 | sb.deleteCharAt(sb.length() - 1); 176 | } 177 | }); 178 | sb.append("\n)"); 179 | 180 | candidates.add( 181 | new Candidate(namespace.name() + "." + cmdName + "(", sb.toString(), null, null, null, 182 | null, true)); 183 | } else { 184 | sb.append("("); 185 | cmd.getArgs().forEach(arg -> { 186 | sb.append(arg.getType() + " " + arg.getName()).append(","); 187 | }); 188 | sb.deleteCharAt(sb.length() - 1); 189 | sb.append(")"); 190 | 191 | candidates.add( 192 | new Candidate(namespace.name() + "." + cmdName + "(", sb.toString(), null, null, null, 193 | null, true)); 194 | } 195 | } 196 | }); 197 | }); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/ReservedWord.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | @FunctionalInterface 20 | public interface ReservedWord { 21 | 22 | void execute(); 23 | } 24 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/Shell.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | import java.io.IOException; 20 | import java.io.PrintWriter; 21 | import java.nio.file.Paths; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | import java.util.concurrent.locks.ReentrantLock; 26 | 27 | import com.alipay.antchain.bridge.pluginserver.cli.command.NamespaceManager; 28 | import com.alipay.antchain.bridge.pluginserver.cli.core.ManagementGrpcClient; 29 | import org.jline.reader.LineReader; 30 | import org.jline.reader.LineReader.Option; 31 | import org.jline.reader.impl.history.DefaultHistory; 32 | import org.jline.terminal.Terminal; 33 | import org.jline.terminal.TerminalBuilder; 34 | 35 | public class Shell { 36 | 37 | private static final String PROMPT = "\033[0;37mps> \033[0m"; 38 | 39 | private final NamespaceManager namespaceManager; 40 | 41 | private Terminal terminal; 42 | 43 | private GlLineReader reader; 44 | 45 | private final Map reservedWord = new HashMap<>(); 46 | 47 | private AtomicBoolean loopRunning = new AtomicBoolean(false); 48 | 49 | private final ReentrantLock shellLock = new ReentrantLock(); 50 | 51 | private final PromptCompleter completer; 52 | 53 | private final ShellProvider shellProvider; 54 | 55 | public final static Runtime RUNTIME = new Runtime(); 56 | 57 | public Shell(ShellProvider shellProvider, PromptCompleter completer, ManagementGrpcClient grpcClient, 58 | NamespaceManager namespaceManager) { 59 | 60 | // 不可扩展参数初始化 61 | init(); 62 | 63 | // 扩展初始化 64 | this.shellProvider = shellProvider; 65 | this.namespaceManager = namespaceManager; 66 | 67 | this.completer = completer; 68 | this.reservedWord.keySet().forEach(reservedWord -> this.completer.addReservedWord(reservedWord)); 69 | 70 | reader.setCompleter(completer); 71 | 72 | // 运行时设置 73 | RUNTIME.setGrpcClient(grpcClient); 74 | } 75 | 76 | void init() { 77 | // init term 78 | try { 79 | terminal = TerminalBuilder.builder() 80 | .system(true) 81 | .build(); 82 | } catch (IOException e) { 83 | throw new RuntimeException("can't open system stream"); 84 | } 85 | 86 | // set printer 87 | RUNTIME.setPrinter(terminal.writer()); 88 | 89 | // init linereader 90 | reader = new GlLineReader(terminal, "mychain-gl", new HashMap<>()); 91 | 92 | reader.setVariable(LineReader.HISTORY_FILE, Paths.get("./clihistory.tmp")); 93 | reader.setHistory(new DefaultHistory(reader)); 94 | 95 | reader.unsetOpt(Option.MENU_COMPLETE); 96 | reader.setOpt(Option.AUTO_LIST); 97 | reader.unsetOpt(Option.AUTO_MENU); 98 | 99 | 100 | // init shell commands 101 | initReservedWord(); 102 | } 103 | 104 | public void start() { 105 | 106 | try { 107 | if (shellLock.tryLock()) { 108 | 109 | if (loopRunning.get()) { 110 | return; 111 | } 112 | 113 | loopRunning.set(true); 114 | 115 | welcome(); 116 | 117 | new Thread(() -> { 118 | // start loop 119 | while (loopRunning.get()) { 120 | String cmd = reader.readLine(PROMPT); 121 | 122 | if (null == cmd || cmd.isEmpty()) { 123 | continue; 124 | } 125 | 126 | try { 127 | if (reservedWord.containsKey(cmd.trim())) { 128 | 129 | reservedWord.get(cmd.trim()).execute(); 130 | continue; 131 | } 132 | 133 | String result = this.shellProvider.execute(cmd); 134 | if (null != result) { 135 | if (result.startsWith("{") || result.startsWith("[")) { 136 | RUNTIME.getPrinter().println(JsonUtil.format(result)); 137 | } else { 138 | RUNTIME.getPrinter().println(result); 139 | } 140 | 141 | } 142 | } catch (Exception e) { 143 | RUNTIME.getPrinter().println("shell evaluate fail:" + e.getMessage()); 144 | } 145 | } 146 | }, "shell_thread").start(); 147 | 148 | } 149 | } finally { 150 | shellLock.unlock(); 151 | } 152 | } 153 | 154 | public String execute(String cmd) { 155 | return this.shellProvider.execute(cmd); 156 | } 157 | 158 | public void stop() { 159 | 160 | loopRunning.set(false); 161 | try { 162 | if (null != RUNTIME.getGrpcClient()) { 163 | RUNTIME.getGrpcClient().shutdown(); 164 | } 165 | } catch (InterruptedException e) { 166 | // not process 167 | } 168 | } 169 | 170 | protected void initReservedWord() { 171 | this.reservedWord.put("exit", this::exit); 172 | this.reservedWord.put("help", this::help); 173 | } 174 | 175 | protected void exit() { 176 | stop(); 177 | } 178 | 179 | protected void help() { 180 | RUNTIME.getPrinter().print(namespaceManager.dump()); 181 | } 182 | 183 | protected void welcome() { 184 | RUNTIME.printer.println( 185 | " ___ __ ______ __ _ ____ _ __\n" + 186 | " / | ____ / /_ / ____// /_ ____ _ (_)____ / __ ) _____ (_)____/ /____ _ ___\n" + 187 | " / /| | / __ \\ / __// / / __ \\ / __ `// // __ \\ / __ |/ ___// // __ // __ `// _ \\\n" + 188 | " / ___ | / / / // /_ / /___ / / / // /_/ // // / / / / /_/ // / / // /_/ // /_/ // __/\n" + 189 | "/_/ |_|/_/ /_/ \\__/ \\____//_/ /_/ \\__,_//_//_/ /_/ /_____//_/ /_/ \\__,_/ \\__, / \\___/\n" + 190 | " /____/ \n" + 191 | " PLUGIN SERVER CLI " + Launcher.getVersion() 192 | ); 193 | RUNTIME.printer.println("\n>>> type help to see all commands..."); 194 | } 195 | 196 | public static class Runtime { 197 | 198 | private PrintWriter printer; 199 | 200 | private ManagementGrpcClient grpcClient; 201 | 202 | void setPrinter(PrintWriter printer) { 203 | 204 | this.printer = printer; 205 | } 206 | 207 | void setGrpcClient(ManagementGrpcClient grpcClient) { 208 | this.grpcClient = grpcClient; 209 | } 210 | 211 | public PrintWriter getPrinter() { 212 | return printer; 213 | } 214 | 215 | public ManagementGrpcClient getGrpcClient() { 216 | return grpcClient; 217 | } 218 | 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /ps-cli/src/main/java/com/alipay/antchain/bridge/pluginserver/cli/shell/ShellProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.cli.shell; 18 | 19 | public interface ShellProvider { 20 | 21 | /** 22 | * 执行命令 23 | * 24 | * @param cmd 25 | */ 26 | String execute(String cmd); 27 | 28 | /** 29 | * shutdown 30 | */ 31 | void shutdown(); 32 | } 33 | -------------------------------------------------------------------------------- /ps-cli/src/main/resources/VERSION: -------------------------------------------------------------------------------- 1 | @project.version@ -------------------------------------------------------------------------------- /ps-cli/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %msg%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ps-cli/src/main/resources/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bin=`dirname "${BASH_SOURCE-$0}"` 4 | CLI_HOME=`cd "$bin"; pwd` 5 | 6 | which java > /dev/null 7 | if [ $? -eq 1 ]; then 8 | echo "no java installed. " 9 | exit 1 10 | fi 11 | 12 | Help=$(cat <<-"HELP" 13 | 14 | start.sh — Start the CLI tool to manage your plugin server 15 | 16 | Usage: 17 | start.sh 18 | 19 | Examples: 20 | 1. print help info: 21 | start.sh -h 22 | 2. identify the port number to start CLI 23 | start.sh -p 9091 24 | 3. identify the server IP to start CLI 25 | start.sh -H 0.0.0.0 26 | 27 | Options: 28 | -h print help info 29 | -p identify the port number to start CLI, default 9091 30 | -H identify the server IP to start CLI, default 127.0.0.1 31 | 32 | HELP 33 | ) 34 | 35 | while getopts "hH:p:" opt 36 | do 37 | case "$opt" in 38 | "h") 39 | echo "$Help" 40 | exit 0 41 | ;; 42 | "H") 43 | HOST_IP="${OPTARG}" 44 | ;; 45 | "p") 46 | PORT=${OPTARG} 47 | ;; 48 | "?") 49 | echo "invalid arguments. " 50 | exit 1 51 | ;; 52 | *) 53 | echo "Unknown error while processing options" 54 | exit 1 55 | ;; 56 | esac 57 | done 58 | 59 | JAR_FILE=`ls ${CLI_HOME}/../lib` 60 | 61 | java -jar ${CLI_HOME}/../lib/${JAR_FILE} -p ${PORT:-9091} -H ${HOST_IP:-127.0.0.1} -------------------------------------------------------------------------------- /ps-pluginmanager/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /ps-pluginmanager/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alipay.antchain.bridge 8 | antchain-bridge-pluginserver 9 | 0.2.3 10 | 11 | 12 | ps-pluginmanager 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | com.alipay.antchain.bridge 23 | antchain-bridge-plugin-manager 24 | 25 | 26 | com.alipay.antchain.bridge 27 | antchain-bridge-spi 28 | 29 | 30 | com.alipay.antchain.bridge 31 | antchain-bridge-commons 32 | 33 | 34 | cn.bitfactory 35 | bid-sdk 36 | 37 | 38 | cn.bitfactory 39 | bif-chain-sdk 40 | 41 | 42 | 43 | 44 | com.alipay.antchain.bridge 45 | ps-service 46 | 47 | 48 | com.alipay.antchain.bridge 49 | ps-service 50 | 51 | 52 | com.alipay.antchain.bridge 53 | ps-service 54 | 55 | 56 | com.alipay.antchain.bridge 57 | ps-service 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /ps-pluginmanager/src/main/java/com/alipay/antchain/bridge/pluginserver/pluginmanager/IPluginManagerWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.pluginmanager; 18 | 19 | import com.alipay.antchain.bridge.plugins.manager.core.IAntChainBridgePlugin; 20 | import com.alipay.antchain.bridge.plugins.spi.bbc.IBBCService; 21 | 22 | import java.util.List; 23 | 24 | public interface IPluginManagerWrapper { 25 | void loadPlugins(); 26 | 27 | void startPlugins(); 28 | 29 | void loadPlugin(String path); 30 | 31 | void startPlugin(String path); 32 | 33 | void stopPlugin(String product); 34 | 35 | void startPluginFromStop(String product); 36 | 37 | void reloadPlugin(String product); 38 | 39 | void reloadPlugin(String product, String path); 40 | 41 | IAntChainBridgePlugin getPlugin(String product); 42 | 43 | boolean hasPlugin(String product); 44 | 45 | List allSupportProducts(); 46 | 47 | IBBCService createBBCService(String product, String domain); 48 | 49 | IBBCService getBBCService(String product, String domain); 50 | 51 | boolean hasDomain(String domain); 52 | 53 | List allRunningDomains(); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /ps-pluginmanager/src/main/java/com/alipay/antchain/bridge/pluginserver/pluginmanager/PluginManagerWrapperImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.pluginmanager; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | import java.nio.file.Path; 21 | import java.nio.file.Paths; 22 | import java.util.*; 23 | import java.util.stream.Collectors; 24 | 25 | import ch.qos.logback.classic.AsyncAppender; 26 | import ch.qos.logback.classic.Level; 27 | import ch.qos.logback.classic.LoggerContext; 28 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder; 29 | import ch.qos.logback.classic.spi.ILoggingEvent; 30 | import ch.qos.logback.core.rolling.RollingFileAppender; 31 | import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy; 32 | import ch.qos.logback.core.util.FileSize; 33 | import cn.hutool.core.collection.ListUtil; 34 | import cn.hutool.core.util.ObjectUtil; 35 | import cn.hutool.core.util.StrUtil; 36 | import com.alipay.antchain.bridge.commons.core.base.CrossChainDomain; 37 | import com.alipay.antchain.bridge.plugins.manager.AntChainBridgePluginManagerFactory; 38 | import com.alipay.antchain.bridge.plugins.manager.core.IAntChainBridgePlugin; 39 | import com.alipay.antchain.bridge.plugins.manager.core.IAntChainBridgePluginManager; 40 | import com.alipay.antchain.bridge.plugins.spi.bbc.IBBCService; 41 | import lombok.extern.slf4j.Slf4j; 42 | import org.pf4j.ClassLoadingStrategy; 43 | import org.slf4j.Logger; 44 | import org.slf4j.LoggerFactory; 45 | import org.springframework.beans.factory.annotation.Autowired; 46 | import org.springframework.beans.factory.annotation.Value; 47 | import org.springframework.stereotype.Component; 48 | 49 | @Slf4j 50 | @Component 51 | public class PluginManagerWrapperImpl implements IPluginManagerWrapper { 52 | 53 | private final IAntChainBridgePluginManager manager; 54 | 55 | private final String bbcLoggerDir; 56 | 57 | @Value("${pluginserver.plugin.log.bbc.max_history:3}") 58 | private int maxBBCLogHistory; 59 | 60 | @Value("${pluginserver.plugin.log.bbc.max_file_size:30mb}") 61 | private String maxBBCLogFileSize; 62 | 63 | @Value("${pluginserver.plugin.log.bbc.level:info}") 64 | private String bbcLogLevel; 65 | 66 | @Value("${pluginserver.plugin.log.bbc.on:true}") 67 | private boolean isBBCLogOn; 68 | 69 | private final Map bbcLoggerMap = new HashMap<>(); 70 | 71 | @Autowired 72 | public PluginManagerWrapperImpl( 73 | @Value("${pluginserver.plugin.repo}") String path, 74 | @Value("${logging.file.path}") String appLogDir, 75 | @Value("${pluginserver.plugin.policy.classloader.resource.ban-with-prefix.APPLICATION:}") String[] resourceBannedPrefixOnAppLevel 76 | ) { 77 | log.info("plugins path: {}", Paths.get(path).toAbsolutePath()); 78 | 79 | this.bbcLoggerDir = Paths.get(appLogDir, "bbc").toAbsolutePath().toString(); 80 | log.info("bbc logger base dir: {}", Paths.get(bbcLoggerDir).toAbsolutePath()); 81 | 82 | this.manager = AntChainBridgePluginManagerFactory.createPluginManager( 83 | path, 84 | ObjectUtil.defaultIfNull(convertPathPrefixBannedMap(resourceBannedPrefixOnAppLevel), new HashMap<>()) 85 | ); 86 | loadPlugins(); 87 | startPlugins(); 88 | } 89 | 90 | private Map> convertPathPrefixBannedMap( 91 | String[] resourceBannedPrefixOnAppLevel 92 | ) { 93 | Map> result = new HashMap<>(); 94 | 95 | Set appSet = new HashSet<>(ListUtil.of(resourceBannedPrefixOnAppLevel)); 96 | result.put(ClassLoadingStrategy.Source.APPLICATION, appSet); 97 | 98 | return result; 99 | } 100 | 101 | @Override 102 | public void loadPlugins() { 103 | manager.loadPlugins(); 104 | } 105 | 106 | @Override 107 | public void startPlugins() { 108 | manager.startPlugins(); 109 | } 110 | 111 | @Override 112 | public void loadPlugin(String path) { 113 | manager.loadPlugin(Paths.get(path)); 114 | } 115 | 116 | @Override 117 | public void startPlugin(String path) { 118 | manager.startPlugin(Paths.get(path)); 119 | } 120 | 121 | @Override 122 | public void stopPlugin(String product) { 123 | manager.stopPlugin(product); 124 | } 125 | 126 | @Override 127 | public void startPluginFromStop(String product) { 128 | manager.startPluginFromStop(product); 129 | } 130 | 131 | @Override 132 | public void reloadPlugin(String product) { 133 | manager.reloadPlugin(product); 134 | } 135 | 136 | @Override 137 | public void reloadPlugin(String product, String path) { 138 | manager.reloadPlugin(product, Paths.get(path)); 139 | } 140 | 141 | @Override 142 | public IAntChainBridgePlugin getPlugin(String product) { 143 | return manager.getPlugin(product); 144 | } 145 | 146 | @Override 147 | public boolean hasPlugin(String product) { 148 | return manager.hasPlugin(product); 149 | } 150 | 151 | @Override 152 | public List allSupportProducts() { 153 | return manager.allSupportProducts(); 154 | } 155 | 156 | @Override 157 | public IBBCService createBBCService(String product, String domain) { 158 | return manager.createBBCService(product, new CrossChainDomain(domain), createBBCServiceLogger(product, domain)); 159 | } 160 | 161 | @Override 162 | public IBBCService getBBCService(String product, String domain) { 163 | return manager.getBBCService(product, new CrossChainDomain(domain)); 164 | } 165 | 166 | @Override 167 | public boolean hasDomain(String domain) { 168 | return manager.hasDomain(new CrossChainDomain(domain)); 169 | } 170 | 171 | @Override 172 | public List allRunningDomains() { 173 | return manager.allRunningDomains().stream().map(CrossChainDomain::toString).collect(Collectors.toList()); 174 | } 175 | 176 | private Logger createBBCServiceLogger(String product, String domain) { 177 | if (!isBBCLogOn) { 178 | return null; 179 | } 180 | String loggerName = getLoggerName(product, domain); 181 | if (bbcLoggerMap.containsKey(loggerName) && ObjectUtil.isNotNull(bbcLoggerMap.get(loggerName))) { 182 | return bbcLoggerMap.get(loggerName); 183 | } 184 | Path logFile = Paths.get(bbcLoggerDir, product, domain + ".log"); 185 | Logger logger = LoggerFactory.getLogger(loggerName); 186 | if (logger instanceof ch.qos.logback.classic.Logger) { 187 | log.debug("using logback for bbc logger"); 188 | 189 | LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); 190 | 191 | PatternLayoutEncoder encoder = new PatternLayoutEncoder(); 192 | encoder.setContext(context); 193 | encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"); 194 | encoder.setCharset(StandardCharsets.UTF_8); 195 | encoder.start(); 196 | 197 | SizeAndTimeBasedRollingPolicy rollingPolicy = new SizeAndTimeBasedRollingPolicy<>(); 198 | rollingPolicy.setContext(context); 199 | rollingPolicy.setFileNamePattern(logFile + ".%d{yyyy-MM-dd}.%i"); 200 | rollingPolicy.setMaxHistory(maxBBCLogHistory); 201 | rollingPolicy.setMaxFileSize(FileSize.valueOf(maxBBCLogFileSize)); 202 | 203 | RollingFileAppender appender = new RollingFileAppender<>(); 204 | appender.setContext(context); 205 | appender.setEncoder(encoder); 206 | appender.setFile(logFile.toString()); 207 | appender.setRollingPolicy(rollingPolicy); 208 | 209 | rollingPolicy.setParent(appender); 210 | rollingPolicy.start(); 211 | appender.start(); 212 | 213 | AsyncAppender asyncAppender = new AsyncAppender(); 214 | asyncAppender.setContext(context); 215 | asyncAppender.setName(loggerName); 216 | asyncAppender.addAppender(appender); 217 | asyncAppender.start(); 218 | 219 | ch.qos.logback.classic.Logger loggerLogback = (ch.qos.logback.classic.Logger) logger; 220 | loggerLogback.setLevel(Level.toLevel(bbcLogLevel)); 221 | loggerLogback.setAdditive(false); 222 | loggerLogback.addAppender(asyncAppender); 223 | 224 | bbcLoggerMap.put(loggerName, loggerLogback); 225 | log.info("bbc logger {} created", loggerName); 226 | 227 | return loggerLogback; 228 | } 229 | 230 | log.debug("logger library not support for now"); 231 | return null; 232 | } 233 | 234 | private String getLoggerName(String product, String domain) { 235 | return StrUtil.format("{}::{}", product, domain); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /ps-server/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /ps-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alipay.antchain.bridge 8 | antchain-bridge-pluginserver 9 | 0.2.3 10 | 11 | 12 | ps-server 13 | 14 | 15 | 8 16 | 8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | net.devh 23 | grpc-server-spring-boot-starter 24 | 25 | 26 | 27 | com.alipay.antchain.bridge 28 | ps-service 29 | 30 | 31 | 32 | com.alipay.antchain.bridge 33 | ps-pluginmanager 34 | 35 | 36 | 37 | io.netty 38 | netty-tcnative-boringssl-static 39 | 40 | 41 | 42 | com.alipay.antchain.bridge 43 | antchain-bridge-plugin-manager 44 | 45 | 46 | 47 | com.alipay.antchain.bridge 48 | antchain-bridge-spi 49 | 50 | 51 | 52 | com.alipay.antchain.bridge 53 | antchain-bridge-plugin-lib 54 | 55 | 56 | 57 | org.pf4j 58 | pf4j 59 | 60 | 61 | 62 | org.projectlombok 63 | lombok 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /ps-server/src/main/java/com/alipay/antchain/bridge/pluginserver/server/PluginManagementServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.server; 18 | 19 | import java.util.Comparator; 20 | import java.util.stream.Collectors; 21 | import javax.annotation.Resource; 22 | 23 | import cn.hutool.core.util.ObjectUtil; 24 | import com.alipay.antchain.bridge.plugins.spi.bbc.IBBCService; 25 | import com.alipay.antchain.bridge.pluginserver.managementservice.*; 26 | import com.alipay.antchain.bridge.pluginserver.pluginmanager.IPluginManagerWrapper; 27 | import com.alipay.antchain.bridge.pluginserver.server.exception.ServerErrorCodeEnum; 28 | import io.grpc.stub.StreamObserver; 29 | import lombok.extern.slf4j.Slf4j; 30 | import org.springframework.stereotype.Component; 31 | 32 | @Component 33 | @Slf4j 34 | public class PluginManagementServiceImpl extends ManagementServiceGrpc.ManagementServiceImplBase { 35 | 36 | @Resource 37 | private IPluginManagerWrapper pluginManagerWrapper; 38 | 39 | /** 40 | *
 41 |      * maintenance personnel may invoke this interface to load, unload, start, and stop plugins
 42 |      * 
43 | */ 44 | public void managePlugin(PluginManageRequest request, StreamObserver responseObserver) { 45 | String path = request.getPath(); 46 | String product = request.getProduct(); 47 | log.info("ManageRequest [path: {}, product: {}, request: {}]", path, product, request.getType()); 48 | 49 | ManageResponse resp; 50 | 51 | switch (request.getType()){ 52 | case LOAD_PLUGINS: 53 | resp = handleLoadPlugins(); 54 | break; 55 | case START_PLUGINS: 56 | resp = handleStartPlugins(); 57 | break; 58 | case LOAD_PLUGIN: 59 | resp = handleLoadPlugin(path); 60 | break; 61 | case START_PLUGIN: 62 | resp = handleStartPlugin(path); 63 | break; 64 | case STOP_PLUGIN: 65 | resp = handleStopPlugin(product); 66 | break; 67 | case START_PLUGIN_FROM_STOP: 68 | resp = handleStartPluginFromStop(product); 69 | break; 70 | case RELOAD_PLUGIN: 71 | resp = handleReloadPlugin(product); 72 | break; 73 | case RELOAD_PLUGIN_IN_NEW_PATH: 74 | resp = handleReloadPluginInNewPath(product, path); 75 | break; 76 | default: 77 | log.error("managePlugin fail [path: {}, product: {}, request: {}, errorCode: {}, errorMsg: {}]", path, product, request.getType(), ServerErrorCodeEnum.UNSUPPORT_MANAGE_REQUEST_ERROR.getErrorCode(), ServerErrorCodeEnum.UNSUPPORT_MANAGE_REQUEST_ERROR.getShortMsg()); 78 | resp = ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.UNSUPPORT_MANAGE_REQUEST_ERROR); 79 | break; 80 | } 81 | 82 | responseObserver.onNext(resp); 83 | responseObserver.onCompleted(); 84 | } 85 | 86 | private ManageResponse handleLoadPlugins() { 87 | try { 88 | pluginManagerWrapper.loadPlugins(); 89 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 90 | } catch (Exception e){ 91 | log.error("manage(handleLoadPlugins) fail [errorCode: {}, errorMsg: {}]", ServerErrorCodeEnum.MANAGE_LOAD_PLUGINS_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_LOAD_PLUGINS_ERROR.getShortMsg(), e); 92 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_LOAD_PLUGINS_ERROR, e.toString()); 93 | } 94 | } 95 | 96 | private ManageResponse handleStartPlugins() { 97 | try { 98 | pluginManagerWrapper.startPlugins(); 99 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 100 | } catch (Exception e){ 101 | log.error("manage(handleStartPlugins) fail [errorCode: {}, errorMsg: {}]", ServerErrorCodeEnum.MANAGE_START_PLUGINS_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_START_PLUGINS_ERROR.getShortMsg(), e); 102 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_START_PLUGINS_ERROR, e.toString()); 103 | } 104 | } 105 | 106 | private ManageResponse handleLoadPlugin(String path) { 107 | try { 108 | pluginManagerWrapper.loadPlugin(path); 109 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 110 | } catch (Exception e){ 111 | log.error("manage(handleLoadPlugin) fail [path: {}, errorCode: {}, errorMsg: {}]", path, ServerErrorCodeEnum.MANAGE_LOAD_PLUGIN_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_LOAD_PLUGIN_ERROR.getShortMsg(), e); 112 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_LOAD_PLUGIN_ERROR, e.toString()); 113 | } 114 | } 115 | 116 | private ManageResponse handleStartPlugin(String path) { 117 | try { 118 | pluginManagerWrapper.startPlugin(path); 119 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 120 | } catch (Exception e){ 121 | log.error("manage(handleStartPlugin) fail [path: {}, errorCode: {}, errorMsg: {}]", path, ServerErrorCodeEnum.MANAGE_START_PLUGIN_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_START_PLUGIN_ERROR.getShortMsg(), e); 122 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_START_PLUGIN_ERROR, e.toString()); 123 | } 124 | } 125 | 126 | private ManageResponse handleStopPlugin(String product) { 127 | try { 128 | pluginManagerWrapper.stopPlugin(product); 129 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 130 | } catch (Exception e){ 131 | log.error("manage(handleStopPlugin) fail [product: {}, errorCode: {}, errorMsg: {}]", product, ServerErrorCodeEnum.MANAGE_STOP_PLUGIN_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_STOP_PLUGIN_ERROR.getShortMsg(), e); 132 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_STOP_PLUGIN_ERROR, e.toString()); 133 | } 134 | } 135 | 136 | private ManageResponse handleStartPluginFromStop(String product) { 137 | try { 138 | pluginManagerWrapper.startPluginFromStop(product); 139 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 140 | } catch (Exception e){ 141 | log.error("manage(handleStartPluginFromStop) fail [product: {}, errorCode: {}, errorMsg: {}]", product, ServerErrorCodeEnum.MANAGE_START_PLUGIN_FROM_STOP_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_START_PLUGIN_FROM_STOP_ERROR.getShortMsg(), e); 142 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_START_PLUGIN_FROM_STOP_ERROR, e.toString()); 143 | } 144 | } 145 | 146 | private ManageResponse handleReloadPlugin(String product) { 147 | try { 148 | pluginManagerWrapper.reloadPlugin(product); 149 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 150 | } catch (Exception e){ 151 | log.error("manage(handleReloadPlugin) fail [product: {}, errorCode: {}, errorMsg: {}]", product, ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_ERROR.getErrorCode(), ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_ERROR.getShortMsg(), e); 152 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_ERROR, e.toString()); 153 | } 154 | } 155 | 156 | private ManageResponse handleReloadPluginInNewPath(String product, String path) { 157 | try { 158 | pluginManagerWrapper.reloadPlugin(product, path); 159 | return ResponseBuilder.buildPluginManageSuccessResp(PluginManageResp.newBuilder()); 160 | } catch (Exception e){ 161 | log.error("manage(handleReloadPluginInNewPath) fail [product: {}, path: {}, errorCode: {}, errorMsg: {}]", ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_IN_NEW_PATH_ERROR.getErrorCode(), product, path, ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_IN_NEW_PATH_ERROR.getShortMsg(), e); 162 | return ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_RELOAD_PLUGIN_IN_NEW_PATH_ERROR, e.toString()); 163 | } 164 | } 165 | 166 | /** 167 | *
168 |      * return whether the plugins of the products are supported
169 |      * 
170 | */ 171 | @Override 172 | public void hasPlugins(HasPluginsRequest request, StreamObserver responseObserver) { 173 | responseObserver.onNext( 174 | ResponseBuilder.buildHasPluginsResp( 175 | HasPluginsResp.newBuilder() 176 | .putAllResults( 177 | request.getProductsList().stream() 178 | .distinct() 179 | .collect(Collectors.toMap(p -> p, p -> pluginManagerWrapper.hasPlugin(p))) 180 | ) 181 | ) 182 | ); 183 | responseObserver.onCompleted(); 184 | } 185 | 186 | /** 187 | *
188 |      * return all supported plugin products
189 |      * 
190 | */ 191 | @Override 192 | public void allPlugins(AllPluginsRequest request, StreamObserver responseObserver) { 193 | responseObserver.onNext( 194 | ResponseBuilder.buildAllPluginsResp( 195 | AllPluginsResp.newBuilder().addAllProducts(pluginManagerWrapper.allSupportProducts().stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList())) 196 | ) 197 | ); 198 | responseObserver.onCompleted(); 199 | } 200 | 201 | /** 202 | *
203 |      * return whether the chains of the domains are running
204 |      * 
205 | */ 206 | @Override 207 | public void hasDomains(HasDomainsRequest request, StreamObserver responseObserver) { 208 | responseObserver.onNext(ResponseBuilder.buildHasDomainsResp(HasDomainsResp.newBuilder() 209 | .putAllResults(request.getDomainsList().stream().distinct().collect(Collectors.toMap(d -> d, d -> pluginManagerWrapper.hasDomain(d)))) 210 | ) 211 | ); 212 | responseObserver.onCompleted(); 213 | } 214 | 215 | /** 216 | *
217 |      * return domains of all running chains
218 |      * 
219 | */ 220 | @Override 221 | public void allDomains(AllDomainsRequest request, StreamObserver responseObserver) { 222 | responseObserver.onNext( 223 | ResponseBuilder.buildAllDomainsResp( 224 | AllDomainsResp.newBuilder().addAllDomains(pluginManagerWrapper.allRunningDomains().stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList())) 225 | ) 226 | ); 227 | responseObserver.onCompleted(); 228 | } 229 | 230 | @Override 231 | public void restartBBC(RestartBBCRequest request, StreamObserver responseObserver) { 232 | if (!pluginManagerWrapper.hasPlugin(request.getProduct())) { 233 | responseObserver.onNext( 234 | ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_RESTART_BBC_ERROR, "product not found") 235 | ); 236 | responseObserver.onCompleted(); 237 | return; 238 | } 239 | if (!pluginManagerWrapper.hasDomain(request.getDomain())) { 240 | responseObserver.onNext( 241 | ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_RESTART_BBC_ERROR, "domain not found") 242 | ); 243 | responseObserver.onCompleted(); 244 | return; 245 | } 246 | try { 247 | IBBCService oldBbcService = pluginManagerWrapper.getBBCService(request.getProduct(), request.getDomain()); 248 | if (ObjectUtil.isNull(oldBbcService)) { 249 | throw new RuntimeException("null BBC service for domain " + request.getDomain()); 250 | } 251 | IBBCService newBbcService = pluginManagerWrapper.createBBCService(request.getProduct(), request.getDomain()); 252 | newBbcService.startup(oldBbcService.getContext()); 253 | } catch (Exception e) { 254 | log.error("restartBBC fail [errorCode: {}, errorMsg: {}]", 255 | ServerErrorCodeEnum.MANAGE_RESTART_BBC_ERROR.getErrorCode(), 256 | ServerErrorCodeEnum.MANAGE_RESTART_BBC_ERROR.getShortMsg(), e); 257 | responseObserver.onNext( 258 | ResponseBuilder.buildFailManageResp(ServerErrorCodeEnum.MANAGE_RESTART_BBC_ERROR, "UNKNOWN") 259 | ); 260 | responseObserver.onCompleted(); 261 | return; 262 | } 263 | responseObserver.onNext( 264 | ResponseBuilder.buildRestartBBCResp(RestartBBCResp.newBuilder()) 265 | ); 266 | responseObserver.onCompleted(); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /ps-server/src/main/java/com/alipay/antchain/bridge/pluginserver/server/ResponseBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.server; 18 | 19 | import com.alipay.antchain.bridge.pluginserver.managementservice.*; 20 | import com.alipay.antchain.bridge.pluginserver.server.exception.ServerErrorCodeEnum; 21 | import com.alipay.antchain.bridge.pluginserver.service.*; 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | @Slf4j 25 | public class ResponseBuilder { 26 | 27 | public static Response buildBBCSuccessResp(CallBBCResponse.Builder respBuilder) { 28 | log.debug("call bbc service response success"); 29 | 30 | return Response.newBuilder() 31 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 32 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 33 | .setBbcResp(respBuilder).build(); 34 | } 35 | 36 | public static Response buildHeartbeatSuccessResp(HeartbeatResponse.Builder respBuilder) { 37 | log.debug("HeartbeatResponse, domains: {}, product: {}", respBuilder.getDomainsList(), respBuilder.getProductsList()); 38 | 39 | return Response.newBuilder() 40 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 41 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 42 | .setHeartbeatResp(respBuilder).build(); 43 | } 44 | 45 | public static Response buildIfProductSupportSuccessResp(IfProductSupportResponse.Builder respBuilder) { 46 | log.debug("IfProductSupportResponse: {}", respBuilder.getResults()); 47 | 48 | return Response.newBuilder() 49 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 50 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 51 | .setIfProductSupportResp(respBuilder).build(); 52 | } 53 | 54 | public static Response buildIfDomainAliveSuccessResp(IfDomainAliveResponse.Builder respBuilder) { 55 | log.debug("IfDomainAliveResponse: {}", respBuilder.getResults()); 56 | 57 | return Response.newBuilder() 58 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 59 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 60 | .setIfDomainAliveResp(respBuilder).build(); 61 | } 62 | 63 | public static Response buildFailResp(ServerErrorCodeEnum errorCodeEnum) { 64 | 65 | return Response.newBuilder() 66 | .setCode(errorCodeEnum.getErrorCode()) 67 | .setErrorMsg(errorCodeEnum.getShortMsg()).build(); 68 | } 69 | 70 | public static Response buildFailResp(ServerErrorCodeEnum errorCodeEnum, String longMsg) { 71 | 72 | return Response.newBuilder() 73 | .setCode(errorCodeEnum.getErrorCode()) 74 | .setErrorMsg(longMsg).build(); 75 | } 76 | 77 | // ManageResponse builder ====================================== 78 | 79 | public static ManageResponse buildPluginManageSuccessResp(PluginManageResp.Builder respBuilder) { 80 | log.debug("plugin manage response success"); 81 | 82 | return ManageResponse.newBuilder() 83 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 84 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 85 | .setPluginManageResp(respBuilder).build(); 86 | } 87 | 88 | public static ManageResponse buildHasPluginsResp(HasPluginsResp.Builder respBuilder) { 89 | log.debug("HasPluginsResponse: {}", respBuilder.getResults()); 90 | 91 | return ManageResponse.newBuilder() 92 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 93 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 94 | .setHasPluginsResp(respBuilder).build(); 95 | } 96 | 97 | public static ManageResponse buildAllPluginsResp(AllPluginsResp.Builder respBuilder) { 98 | log.debug("AllPluginResponse: {}", respBuilder.getProductsList()); 99 | 100 | return ManageResponse.newBuilder() 101 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 102 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 103 | .setAllPluginsResp(respBuilder).build(); 104 | } 105 | 106 | public static ManageResponse buildHasDomainsResp(HasDomainsResp.Builder respBuilder) { 107 | log.debug("HasDomainsResponse: {}", respBuilder.getResults()); 108 | 109 | return ManageResponse.newBuilder() 110 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 111 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 112 | .setHasDomainsResp(respBuilder).build(); 113 | } 114 | 115 | public static ManageResponse buildAllDomainsResp(AllDomainsResp.Builder respBuilder) { 116 | log.debug("AllDomainsResponse: {}", respBuilder.getDomainsList()); 117 | 118 | return ManageResponse.newBuilder() 119 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 120 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 121 | .setAllDomainsResp(respBuilder).build(); 122 | } 123 | 124 | public static ManageResponse buildRestartBBCResp(RestartBBCResp.Builder respBuilder) { 125 | log.debug("restart bbc service success"); 126 | return ManageResponse.newBuilder() 127 | .setCode(ServerErrorCodeEnum.SUCCESS.getErrorCode()) 128 | .setErrorMsg(ServerErrorCodeEnum.SUCCESS.getShortMsg()) 129 | .setRestartBBCResp(respBuilder) 130 | .build(); 131 | } 132 | 133 | public static ManageResponse buildFailManageResp(ServerErrorCodeEnum errorCodeEnum) { 134 | 135 | return ManageResponse.newBuilder() 136 | .setCode(errorCodeEnum.getErrorCode()) 137 | .setErrorMsg(errorCodeEnum.getShortMsg()).build(); 138 | } 139 | 140 | public static ManageResponse buildFailManageResp(ServerErrorCodeEnum errorCodeEnum, String longMsg) { 141 | 142 | return ManageResponse.newBuilder() 143 | .setCode(errorCodeEnum.getErrorCode()) 144 | .setErrorMsg(longMsg).build(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /ps-server/src/main/java/com/alipay/antchain/bridge/pluginserver/server/exception/ServerErrorCodeEnum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Ant Group 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.alipay.antchain.bridge.pluginserver.server.exception; 18 | 19 | import lombok.Getter; 20 | 21 | @Getter 22 | public enum ServerErrorCodeEnum { 23 | // TODO: add element when you need 24 | 25 | SUCCESS(0, "success"), 26 | 27 | UNSUPPORT_BBC_REQUEST_ERROR(200, "unsupport bbc request type"), 28 | 29 | BBC_GET_SERVICE_ERROR(201, "[bbc] get service failed"), 30 | 31 | BBC_CREATE_ERROR(202, "[bbc] create service failed"), 32 | 33 | BBC_STARTUP_ERROR(203, "[bbc] start up failed"), 34 | 35 | BBC_SHUTDOWN_ERROR(204, "[bbc] shut down failed"), 36 | 37 | BBC_GETCONTEXT_ERROR(205, "[bbc] get context failed"), 38 | 39 | BBC_SETUPSDPMESSAGECONTRACT_ERROR(206, "[bbc] set up sdp contract failed"), 40 | 41 | BBC_SETUPAUTHMESSAGECONTRACT_ERROR(207, "[bbc] set up am contract failed"), 42 | 43 | BBC_SETPROTOCOL_ERROR(208, "[bbc] set protocol failed"), 44 | 45 | BBC_SETAMCONTRACT_ERROR(209, "[bbc] set am contract failed"), 46 | 47 | BBC_ADDVALIDRELAYER_ERROR(210, "[bbc] add valid relayer failed"), 48 | 49 | BBC_RELAYAUTHMESSAGE_ERROR(211, "[bbc] forward relayer auth msg failed"), 50 | 51 | BBC_READ_CCMSG_RET_ERROR(212, "[bbc] read cross chain msg receipt failed"), 52 | 53 | BBC_READCROSSCHAINMESSAGESBYHEIGHT_ERROR(213, "[bbc] read cross chain msg by height failed"), 54 | 55 | BBC_QUERYSDPMESSAGESEQ_ERROR(214, "[bbc] query sdp msg sequence failed"), 56 | 57 | BBC_QUERYLATESTHEIGHT_ERROR(215, "[bbc] query latest height failed"), 58 | 59 | BBC_SETLOCALDOMAIN_ERROR(216, "[bbc] set local domain failed"), 60 | 61 | BBC_OBJECT_NOT_STARTED(217, "[bbc] none bbc object started"), 62 | 63 | BBC_PLUGIN_NOT_SUPPORT(218, "[bbc] none plugin found"), 64 | 65 | UNSUPPORT_MANAGE_REQUEST_ERROR(300, "unsupport manage request type"), 66 | 67 | MANAGE_LOAD_PLUGINS_ERROR(301, "[manage] load plugins failed"), 68 | 69 | MANAGE_START_PLUGINS_ERROR(302, "[manage] start plugins failed"), 70 | 71 | MANAGE_LOAD_PLUGIN_ERROR(303, "[manage] load plugin in the specified path failed"), 72 | 73 | MANAGE_START_PLUGIN_ERROR(304, "[manage] start plugin in the specified path failed"), 74 | 75 | MANAGE_STOP_PLUGIN_ERROR(305, "[manage] stop plugin of specified product failed"), 76 | 77 | MANAGE_START_PLUGIN_FROM_STOP_ERROR(306, "[manage] start plugin of specified product from stop failed"), 78 | 79 | MANAGE_RELOAD_PLUGIN_ERROR(307, "[manage] reload plugin failed"), 80 | 81 | MANAGE_RELOAD_PLUGIN_IN_NEW_PATH_ERROR(308, "[manage] reload plugin in new path failed"), 82 | 83 | MANAGE_RESTART_BBC_ERROR(309, "[manage] restart bbc failed"), 84 | 85 | UNKNOWN_ERROR(100, "unknow error"); 86 | 87 | /** 88 | * Error code for errors happened in project {@code antchain-bridge-pluginserver} 89 | */ 90 | private final int errorCode; 91 | 92 | /** 93 | * Every code has a short message to describe the error stuff 94 | */ 95 | private final String shortMsg; 96 | 97 | ServerErrorCodeEnum(int errorCode, String shortMsg) { 98 | this.errorCode = errorCode; 99 | this.shortMsg = shortMsg; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /ps-server/src/main/java/com/alipay/antchain/bridge/pluginserver/server/interceptor/RequestTraceInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.alipay.antchain.bridge.pluginserver.server.interceptor; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | import cn.hutool.core.util.ObjectUtil; 6 | import cn.hutool.core.util.StrUtil; 7 | import io.grpc.*; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | @Slf4j(topic = "req-trace") 11 | public class RequestTraceInterceptor implements ServerInterceptor { 12 | 13 | @Override 14 | public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) { 15 | InetSocketAddress clientAddr = (InetSocketAddress) call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR); 16 | if (StrUtil.equalsIgnoreCase(call.getMethodDescriptor().getBareMethodName(), "heartbeat")) { 17 | if (ObjectUtil.isNull(clientAddr)) { 18 | log.info("heartbeat from relayer without address found"); 19 | } else { 20 | log.info("heartbeat from relayer {}:{}", clientAddr.getHostString(), clientAddr.getPort()); 21 | } 22 | } else if (StrUtil.equalsIgnoreCase(call.getMethodDescriptor().getBareMethodName(), "bbcCall")) { 23 | if (ObjectUtil.isNull(clientAddr)) { 24 | log.debug("bbc call from relayer without address found"); 25 | } else { 26 | log.debug("bbc call from relayer {}:{}", clientAddr.getHostString(), clientAddr.getPort()); 27 | } 28 | } 29 | 30 | return next.startCall(call, headers); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ps-service/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /ps-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alipay.antchain.bridge 8 | antchain-bridge-pluginserver 9 | 0.2.3 10 | 11 | 12 | ps-service 13 | 14 | 15 | 16 | io.grpc 17 | grpc-stub 18 | 19 | 20 | io.grpc 21 | grpc-protobuf 22 | 23 | 24 | 25 | jakarta.annotation 26 | jakarta.annotation-api 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | kr.motd.maven 35 | os-maven-plugin 36 | 1.7.0 37 | 38 | 39 | 40 | 41 | 42 | org.xolstice.maven.plugins 43 | protobuf-maven-plugin 44 | ${protobuf-plugin.version} 45 | 46 | com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} 47 | grpc-java 48 | io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} 49 | 50 | 51 | 52 | 53 | compile 54 | compile-custom 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ps-service/src/main/proto/managementserver.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package com.alipay.antchain.bridge.pluginserver.managementservice; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.alipay.antchain.bridge.pluginserver.managementservice"; 7 | option java_outer_classname = "ManagementRpcServer"; 8 | 9 | message PluginManageRequest{ 10 | enum Type{ 11 | // load all plugins in the default path 12 | LOAD_PLUGINS = 0; 13 | // start all plugins in the default path 14 | START_PLUGINS = 1; 15 | // load the specified plugin in the specified path 16 | LOAD_PLUGIN = 2; 17 | // start the specified plugin in the specified path 18 | START_PLUGIN = 3; 19 | // stop the specified plugin in the specified path 20 | STOP_PLUGIN = 4; 21 | // start the stopped plugin in the specified path 22 | START_PLUGIN_FROM_STOP = 5; 23 | // reload the specified plugin (plugin not started) 24 | RELOAD_PLUGIN = 6; 25 | // reload the specified plugin from the new path (plugin not started) 26 | RELOAD_PLUGIN_IN_NEW_PATH = 7; 27 | } 28 | 29 | Type type = 1; 30 | string path = 2; 31 | string product = 3; 32 | } 33 | 34 | message HasPluginsRequest{ 35 | repeated string products = 1; 36 | } 37 | 38 | message AllPluginsRequest{ 39 | } 40 | 41 | message HasDomainsRequest{ 42 | repeated string domains = 1; 43 | } 44 | 45 | message AllDomainsRequest{ 46 | } 47 | 48 | message RestartBBCRequest { 49 | string product = 1; 50 | string domain = 2; 51 | } 52 | 53 | message ManageResponse { 54 | uint32 code = 1; 55 | string errorMsg = 2; 56 | oneof manageResp { 57 | PluginManageResp pluginManageResp = 3; 58 | HasPluginsResp hasPluginsResp = 4; 59 | AllPluginsResp allPluginsResp = 5; 60 | HasDomainsResp hasDomainsResp = 6; 61 | AllDomainsResp allDomainsResp = 7; 62 | RestartBBCResp restartBBCResp = 8; 63 | } 64 | } 65 | 66 | message PluginManageResp{ 67 | // stay empty body for now, maybe fill some stuff in future 68 | } 69 | 70 | message HasPluginsResp{ 71 | // key : which product 72 | // value : support or not 73 | map results = 1; 74 | } 75 | 76 | message AllPluginsResp { 77 | repeated string products = 1; 78 | } 79 | 80 | message HasDomainsResp { 81 | // key : which chain 82 | // value : running or not 83 | map results = 1; 84 | } 85 | 86 | message AllDomainsResp { 87 | repeated string domains = 1; 88 | } 89 | 90 | message RestartBBCResp { 91 | } 92 | 93 | service ManagementService { 94 | 95 | // maintenance personnel may invoke this interface to load, unload, start, and stop plugins 96 | rpc managePlugin(PluginManageRequest) returns (ManageResponse) {} 97 | 98 | // return whether the plugins of the products are supported 99 | rpc hasPlugins(HasPluginsRequest) returns (ManageResponse) {} 100 | 101 | // return all supported plugin products 102 | rpc allPlugins(AllPluginsRequest) returns (ManageResponse) {} 103 | 104 | // return whether the chains of the domains are running 105 | rpc hasDomains(HasDomainsRequest) returns (ManageResponse) {} 106 | 107 | // return domains of all running chains 108 | rpc allDomains(AllDomainsRequest) returns (ManageResponse) {} 109 | 110 | // restart the bbc service object from the current plugin files 111 | rpc restartBBC(RestartBBCRequest) returns (ManageResponse) {} 112 | } -------------------------------------------------------------------------------- /ps-service/src/main/proto/pluginserver.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package com.alipay.antchain.bridge.pluginserver.service; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.alipay.antchain.bridge.pluginserver.service"; 7 | option java_outer_classname = "PluginRpcServer"; 8 | 9 | // just empty 10 | message Empty {} 11 | 12 | service CrossChainService { 13 | // Relayer would call this interface to communicate with the `BBCService` object 14 | rpc bbcCall(CallBBCRequest) returns (Response) {} 15 | 16 | // handle heartbeat requests from relayers 17 | rpc heartbeat(Empty) returns (Response) {} 18 | 19 | // return if these blockchain products support or not 20 | rpc ifProductSupport(IfProductSupportRequest) returns (Response) {} 21 | 22 | // return if these blockchain domains alive or not 23 | rpc ifDomainAlive(IfDomainAliveRequest) returns (Response) {} 24 | } 25 | 26 | // heartbeat response 27 | message HeartbeatResponse { 28 | repeated string products = 1; 29 | repeated string domains = 2; 30 | } 31 | 32 | message IfProductSupportRequest { 33 | repeated string products = 1; 34 | } 35 | 36 | message IfProductSupportResponse { 37 | // key : which product 38 | // value : support or not 39 | map results = 1; 40 | } 41 | 42 | message IfDomainAliveRequest { 43 | repeated string domains = 1; 44 | } 45 | 46 | message IfDomainAliveResponse { 47 | // key : which domain 48 | // value : alive or not 49 | map results = 1; 50 | } 51 | 52 | // wrapper for all responses 53 | message Response { 54 | uint32 code = 1; 55 | string errorMsg = 2; 56 | oneof response { 57 | CallBBCResponse bbcResp = 3; 58 | HeartbeatResponse heartbeatResp = 4; 59 | IfProductSupportResponse ifProductSupportResp = 5; 60 | IfDomainAliveResponse ifDomainAliveResp = 6; 61 | } 62 | } 63 | 64 | // messages for `bbcCall` requests 65 | message CallBBCRequest { 66 | // which kind of blockchain for plugin to load 67 | string product = 1; 68 | 69 | // which domain of the blockchain for the `BBCService` to connect with 70 | string domain = 2; 71 | 72 | // biz request for `BBCService` 73 | // basically, evey interface of `BBCService` has a request message defined here. 74 | oneof request { 75 | StartUpRequest startUpReq = 3; 76 | GetContextRequest getContextReq = 4; 77 | ShutdownRequest shutdownReq = 5; 78 | SetupAuthMessageContractRequest setupAuthMessageContractReq = 6; 79 | SetupSDPMessageContractRequest setupSDPMessageContractReq = 7; 80 | SetProtocolRequest setProtocolReq = 8; 81 | RelayAuthMessageRequest relayAuthMessageReq = 9; 82 | SetAmContractRequest setAmContractReq = 10; 83 | ReadCrossChainMessageReceiptRequest readCrossChainMessageReceiptReq = 11; 84 | ReadCrossChainMessagesByHeightRequest readCrossChainMessagesByHeightReq = 12; 85 | QuerySDPMessageSeqRequest querySDPMessageSeqReq = 13; 86 | QueryLatestHeightRequest queryLatestHeightReq = 14; 87 | SetLocalDomainRequest setLocalDomainReq = 15; 88 | } 89 | } 90 | 91 | message StartUpRequest { 92 | bytes rawContext = 1; 93 | } 94 | 95 | message GetContextRequest { 96 | // stay empty body for now, maybe fill some stuff in future 97 | } 98 | 99 | message ShutdownRequest { 100 | // stay empty body for now, maybe fill some stuff in future 101 | } 102 | 103 | message SetupAuthMessageContractRequest { 104 | // stay empty body for now, maybe fill some stuff in future 105 | } 106 | 107 | message SetupSDPMessageContractRequest { 108 | // stay empty body for now, maybe fill some stuff in future 109 | } 110 | 111 | message SetProtocolRequest { 112 | string protocolAddress = 1; 113 | string protocolType = 2; 114 | } 115 | 116 | message RelayAuthMessageRequest { 117 | bytes rawMessage = 1; 118 | } 119 | 120 | message SetAmContractRequest { 121 | string contractAddress = 1; 122 | } 123 | 124 | message ReadCrossChainMessageReceiptRequest { 125 | string txhash = 1; 126 | } 127 | 128 | message ReadCrossChainMessagesByHeightRequest { 129 | uint64 height = 1; 130 | } 131 | 132 | message QuerySDPMessageSeqRequest { 133 | string senderDomain = 1; 134 | string fromAddress = 2; 135 | string receiverDomain = 3; 136 | string toAddress = 4; 137 | } 138 | 139 | message QueryLatestHeightRequest { 140 | // stay empty body for now, maybe fill some stuff in future 141 | } 142 | 143 | message SetLocalDomainRequest { 144 | string domain = 1; 145 | } 146 | 147 | // basic messages. 148 | // same as project `antchain-bridge-commons` 149 | message CrossChainMessageReceipt { 150 | string txhash = 1; 151 | bool confirmed = 2; 152 | bool successful = 3; 153 | string errorMsg = 4; 154 | } 155 | 156 | enum CrossChainMessageType { 157 | AUTH_MSG = 0; 158 | DEVELOPER_DESIGN = 1; 159 | } 160 | 161 | message ProvableLedgerData { 162 | uint64 height = 1; 163 | bytes blockHash = 2; 164 | uint64 timestamp = 3; 165 | bytes ledgerData = 4; 166 | bytes proof = 5; 167 | bytes txHash = 6; 168 | } 169 | 170 | message CrossChainMessage { 171 | CrossChainMessageType type = 1; 172 | bytes message = 2; 173 | ProvableLedgerData provableData = 3; 174 | } 175 | 176 | // messages for `bbcCall` responses 177 | message CallBBCResponse { 178 | oneof response { 179 | GetContextResponse getContextResp = 1; 180 | SetupAuthMessageContractResponse setupAMResp = 2; 181 | SetupSDPMessageContractResponse setupSDPResp = 3; 182 | ReadCrossChainMessageReceiptResponse readCrossChainMessageReceiptResp = 4; 183 | ReadCrossChainMessagesByHeightResponse readCrossChainMessagesByHeightResp = 5; 184 | QuerySDPMessageSeqResponse querySDPMsgSeqResp = 6; 185 | RelayAuthMessageResponse relayAuthMessageResponse = 7; 186 | QueryLatestHeightResponse queryLatestHeightResponse = 8; 187 | } 188 | } 189 | 190 | message GetContextResponse { 191 | bytes rawContext = 1; 192 | } 193 | 194 | enum ContractStatusEnum { 195 | INIT = 0; 196 | CONTRACT_DEPLOYED = 1; 197 | CONTRACT_READY = 2; 198 | CONTRACT_FREEZE = 3; 199 | } 200 | 201 | message AuthMessageContract { 202 | string contractAddress = 1; 203 | ContractStatusEnum status = 2; 204 | } 205 | 206 | message SetupAuthMessageContractResponse { 207 | AuthMessageContract amContract = 1; 208 | } 209 | 210 | message SDPMessageContract { 211 | string contractAddress = 1; 212 | ContractStatusEnum status = 2; 213 | } 214 | 215 | message SetupSDPMessageContractResponse { 216 | SDPMessageContract sdpContract = 1; 217 | } 218 | 219 | message ReadCrossChainMessageReceiptResponse { 220 | CrossChainMessageReceipt receipt = 1; 221 | } 222 | 223 | message ReadCrossChainMessagesByHeightResponse { 224 | repeated CrossChainMessage messageList = 1; 225 | } 226 | 227 | message QuerySDPMessageSeqResponse { 228 | uint64 sequence = 1; 229 | } 230 | 231 | message RelayAuthMessageResponse { 232 | CrossChainMessageReceipt receipt = 1; 233 | } 234 | 235 | message QueryLatestHeightResponse { 236 | uint64 height = 1; 237 | } --------------------------------------------------------------------------------