组件开发指南
什么是组件
组件是一个按照特定规范开发的独立运行的软件程序,组件可接入操作平台与操作平台或其他组件协同实现丰富的功能。包括但不限于:
- 工具集成:浏览器、IDE、资产管理
- 框架支持:DID、跨链、以太坊、Fabric
- 业务整合:数字资产、可信AI
- ...
操作平台内置了很多组件供用户使用,同时支持社区或企业贡献组件,后期上线组件仓库将给用户提供更多的组件选择。
原理
组件是一个独立的服务,基于web、容器和路由转发等技术,单独的沙盒执行环境中运行。每一个组件均有一个全局唯一且以/xbaas开头的路由前缀(如/xbaas/v1/explorer),baas 服务的gateway模块有服务发现和路由转发能力,会将请求组件的流量自动导入到组件服务中。如果组件有前端页面,可以通过iframe方式嵌入到baas前端框架中。
对于开发和测试,您可以通过大众版baas 组件中心的本地加载实现组件部署,一旦您对自己的组件感到满意,可以通过我们组件仓库分发给更多的用户。
服务交互
组件运行可能需要很多数据比如网络详情、节点列表、合约列表、区块高度等等。baas 服务后端开放了OpenApi 支持组件查询baas数据,甚至支持组件前端跨域请求。组件从baas服务中获取到网络和节点地址等信息后可以直接向区块链节点发起请求,做更丰富的链上交易行为。请求路径如下:
- 组件前端 -> baas 后端
- 组件后端 -> baas 后端
- 组件前端 -> 区块链节点
- 组件后端 -> 区块链节点
在API目录中可以查看组件可以调用的接口列表
前端交互
前端交互的背景在于所有的账户保存在baas前端框架中。为了安全考虑,前端框架不会直接将账户暴露给组件,但是会提供合约调用和转账等接口供组件间接调用;这些接口中会有弹窗提示拦截,只有用户同意后才会真正的签名提交。 由于baas架构支持多网络、多账户架构,为了方便组件(比如钱包组件)发起链上交易,前端框架提供网络列表和账户列表查询接口,供组件展示操作网络和账户,如下:
引入父子组件均引入message.js 以发送消息形式请求数据,以接收消息形式获取数据
使用:
1、消息实例(以子页面发送为例)
2、发送消息
发送消息方式:// 获取网络列表
messager.send({request: 'getNets'});
// 获取用户信息列表
messager.send({request: 'getAccounts'});
// 获取合约账户
messager.send({
request: 'getContractAccounts',
params: {
net: {name: 'XuperOS', id: 1},
address: 'gHXnvwSJ7RXiuQq6aH9n69Z5W6wNpUy6M'
}
});
// 获取合约列表
messager.send({
request: 'getContractsList',
params: {
net: {name: 'XuperOS', id: 1},
address: 'gHXnvwSJ7RXiuQq6aH9n69Z5W6wNpUy6M',
contractAccount: 'XC0020194751624976@xuper'
}
});
// 创建合约账户
messager.send({
request: 'createContractAccount',
params: {
net: {name: 'XuperOS', id: 1},
address: 'gHXnvwSJ7RXiuQq6aH9n69Z5W6wNpUy6M'
}
});
// 调用合约
messager.send({
request: 'invokeContract',
params: {
net: {name: 'XuperOS', id: 1},
address: 'gHXnvwSJ7RXiuQq6aH9n69Z5W6wNpUy6M',
invoker: {contractName: 'cdeploy0003', initArgs: {key: 1}, method_name: 'increase', language: 'cpp'}
}
});
3、接收消息
event.data返回:{
netList: {list: []}, // 网络列表; 出错情况:netList: {error: ''},以下均是
accounts: {list: []}, // 用户账户列表
contractAccounts: {list: []}, // 合约账户列表
contracts: {list: []} // 合约列表
}
message.js
export const Messager = class MessengerBuilder {
/**
* target: 发送方或接收方
* domain: 如果是发送方, 则是接收方的domain
* callback: 接收消息后的回调
*
*/
constructor(target, domain, callback) {
this.target = target;
this.domain = domain;
this.onReceiveMessage = this.receive.bind(this);
this.callback = callback;
window.addEventListener('message', this.onReceiveMessage, false);
}
// 发送消息
send(data) {
if (this.target) {
this.target.postMessage(data, this.domain);
}
}
// 设置收到消息后,要发送的消息
setResponse(data) {
this.responseData = data;
}
// 接收消息
receive(event) {
if (event.origin !== this.domain) {
return;
}
this.callback && this.callback(event);
if (this.responseData) {
event.source.postMessage(this.responseData, event.origin);
this.responseData = undefined;
}
}
clear() {
window.removeEventListener('message', this.onReceiveMessage.bind(this));
}
};
数据存储
大众版baas 提供mysql作为组件的存储单元,mysql 的地址、用户名、密码、数据库名称会在部署时根据环境变量传入组件,组件需要实现获取环境变量的能力。参数示例如下:
元数据
组件在本地加载或上传组件仓库时,需要指定几个重要的元数据:名称、版本、描述、贡献者、图标、主页地址、打开方式等等。示例如下:
元数据 | 示例 | 说明 |
---|---|---|
name | 浏览器 | 组件的名称 |
englishName | explorer | 组件英文名 |
version | 1.0.0 | 组件的版本,可用于更新操作 |
desc | 我是超级链浏览器 | 组件用途描述 |
image | xchain/explorer:latest | 镜像名称 |
routePrefix | /xbaas/v1/explorer | 全局唯一,gateway通过路由前缀分发流量必须以xbaas开头,且组件所有接口均使用该前缀 |
port | 8080 | 服务监听的端口号 |
homepage | /xbaas/v1/explorer/index.html | 打开组件时的主页面,无需添加域名或IP前缀 |
author | xx科技有限公司 | 贡献者公司或个人 |
author_icon | xxx.jpg | 用于贡献者标识logo |
所有元数据以json形式记录在 manifest.json 文件中用于后续组件导入和传播:
{
"name":"浏览器",
"englishName":"explorer",
"version":"1.0.0",
"desc":"我是超级链浏览器",
"image":"xchain/explorer:latest",
"routePrefix":"/xbaas/explorer",
"port":8080,
"homepage":"/xbaas/explorer/index.html",
"author":"xx 科技有限公司"
}
测试发布
测试及发布流程详见:组件市场