diff --git a/.travis.yml b/.travis.yml index 5b97a3f3..36549615 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ dist: trusty install: - docker pull hyperchaincn/hvmd - docker run -d --rm --name=hvmd -p 8091:9999 hyperchaincn/hvmd + - docker run -d --name myrabbitmq -p 5672:5672 -p 15672:15672 docker.io/rabbitmq:latest - wget https://github.com/hyperchain/hyperchain/releases/download/v1.0.0/hyperchain-solo-1.0.0-8b68028-20190516-Ubuntu-16.04.tar.gz - tar zxvf hyperchain-solo-1.0.0-8b68028-20190516-Ubuntu-16.04.tar.gz diff --git a/README.md b/README.md index aaa47b29..7c3cc647 100644 --- a/README.md +++ b/README.md @@ -93,4 +93,4 @@ Decoder.decodeHVM(receiptResponse1.getRet(), String.class); If you have any suggestions or idea, please submit issue in this project! ## doc -If you want to know more about LiteSDK, you can read manual at [here](doc/hyperchain litesdk document.md). \ No newline at end of file +If you want to know more about LiteSDK, you can read manual at [here](doc/hyperchain_litesdk_document.md). \ No newline at end of file diff --git a/doc/hyperchain litesdk document.md b/doc/hyperchain_litesdk_document.md similarity index 86% rename from doc/hyperchain litesdk document.md rename to doc/hyperchain_litesdk_document.md index 60613330..1de3d6a1 100644 --- a/doc/hyperchain litesdk document.md +++ b/doc/hyperchain_litesdk_document.md @@ -1,3 +1,4 @@ + ## 第一章. 前言 **LiteSDK**是一个**轻量JavaSDK工具**,提供与Hyperchain区块链平台交互的接口以及一些处理工具。该文档⾯向Hyperchain区块链平台的应⽤开发者,提供hyperchain Java SDK的 使⽤指南。 @@ -17,9 +18,11 @@ HttpProvider httpProvider = new DefaultHttpProvider.Builder() .build(); ``` + * `setUrl()`可以设置连接的节点**URL**(格式为**ip+jsonRPC端口**); * `https()`设置启动**https协议**连接并设置使用的证书(需要传的参数类型为输入流)。 + ### 2.2 创建ProvideManager对象 每个节点的连接都需要一个`HttpProvider`,而`ProvideManager`负责集成、管理这些`HttpProvider`,创建`ProvideManager`有两种方式,一种是通过`createManager()`创建,另一种是和`HttpProvider`一样通过**Builder**模式创建。使用前者创建会使用`ProvideManager`的默认配置参数,而如果想定制更多的属性则需要通过后者的方式创建,示例如下: @@ -36,13 +39,16 @@ providerManager = new ProviderManager.Builder() .build(); ``` -方式1:只需要传`HttpProvider`对象,其他都使用`ProvideManager`的默认配置,如不启用证书、使用的**namespace**配置项为**global**。 +方式1: + +​ 只需要传`HttpProvider`对象,其他都使用`ProvideManager`的默认配置,如不启用证书、使用的**namespace**配置项为**global**。 方式2: * `namespace()`可以设置对应的**namespace名**; * `providers()`设置需要管理的`HttpProvider`对象们; * `enableTCert()`设置使用的证书(**需要传的参数类型为输入流)**。注:例子中未出现的方法还有一个`cfca(InputStream sdkCert, InputStream sdkCertPriv)`,功能与`enableTCert()`相同,两者的区别是证书校验是否通过**cfca机构**,且在创建`ProvideManager`对象过程中两个方法只能使用其中一个。 + ### 2.3 创建服务 相关的一类服务集合由一个专门的`Service`接口管理,并通过对应的实现类实现具体的创建过程(如封装发送请求需要附带的参数)。**LiteSDK**通过`ServiceManager`类负责管理创建所有的`Service`对象,以下是一个创建获取节点信息的服务的例子: @@ -76,7 +82,30 @@ System.out.println(nodeResponse.getNodes()); ## 第三章. 交易 -**LiteSDK**的交易接口分为两类:一类**是普通的转账交易,不涉及虚拟机**,一类是**合约交易,和虚拟机相关**。两者虽然都名为交易,但实际执行的功能和应用场景都不同,该章主要说明如何使用, +**LiteSDK**的交易接口分为两类:一类**是普通的转账交易,不涉及虚拟机**,一类是**合约交易,和虚拟机相关**。两者虽然都名为交易,但实际执行的功能和应用场景都不同。 + + +### 转账交易 + +TODO + +### 合约接口 + +以交易体结构为核心的交易主要应用在合约交易上,即将想要执行的操作和数据封装成一笔交易体,再调用合约服务(`ContractService`)的接口去执行。 + +LiteSDK的合约接口较特殊,目前提供了**部署合约、调用合约、管理合约**三种接口。 + +```java +public interface ContractService { + Request deploy(Transaction transaction, int... nodeIds); + + Request invoke(Transaction transaction, int... nodeIds); + + Request maintain(Transaction transaction, int... nodeIds); +} +``` + +根据要创建的合约服务不同,封装的`Transaction`交易体也会不同。**并且LiteSDK支持HVM、EVM两种形式的合约**,这两种也会影响到交易体的创建。 ### 账户创建 @@ -105,7 +134,7 @@ public interface AccountService { } ``` -### 交易体创建 +#### 交易体创建 **LiteSDK**使用**Builder**模式来负责对`Transaction`的创建,通过调用`build()`函数来获取到`Transaction`实例。HVM和EVM分别有各自的**Builder**:`HVMBuilder`、`EVMBuilder`,继承同一个父类`Builer`。目前**Builder**模式提供了五种交易体的封装,分别对应**部署合约、调用合约、升级合约、冻结合约、解冻合约**,其中前两个服务的交易体分别定义在HVM、EVM各自的`Builder`子类中,后三者都是**管理合约**这一服务的子服务,定义在父类`Builder`中。 @@ -131,29 +160,6 @@ class EVMBuilder extends Builder { 下面是创建各个服务的交易体`Transaction`的实例。 -### 转账交易 - -TODO - -### 合约接口 - -以交易体结构为核心的交易主要应用在合约交易上,即将想要执行的操作和数据封装成一笔交易体,再调用合约服务(`ContractService`)的接口去执行。 - -LiteSDK的合约接口较特殊,目前提供了**部署合约、调用合约、管理合约**三种接口。 - -```java -public interface ContractService { - Request deploy(Transaction transaction, int... nodeIds); - - Request invoke(Transaction transaction, int... nodeIds); - - Request maintain(Transaction transaction, int... nodeIds); -} -``` - -根据要创建的合约服务不同,封装的`Transaction`交易体也会不同。**并且LiteSDK支持HVM、EVM两种形式的合约**,这两种也会影响到交易体的创建。 - - #### 部署合约 ##### HVM @@ -253,7 +259,7 @@ Transaction transaction = new Transaction.EVMBuilder(account.getAddress()).unfre ### 交易体签名 -通过`Transaction`提供的`sign()`方法,需要指定Account对象。 +通过`Transaction`提供的`sign()`方法,需要指定`Account`对象。 ```java transaction.sign(account); @@ -278,9 +284,9 @@ ReceiptResponse receiptResponse = contractRequest.send().polling(); #### -## 第四章. NodeService相关接口 +## 第五章. NodeService相关接口 -### 4.1 获取节点信息 +### 5.1 获取节点信息 参数 @@ -288,4 +294,76 @@ ReceiptResponse receiptResponse = contractRequest.send().polling(); ```java Request getNodes(int... ids); +``` + + + +## 第六章. MQ接口(MQService) + +### 6.1 通知MQ服务器正常工作 + +参数 + ++ nodeIds 说明请求向哪些节点发送 + +```java +Request informNormal(int... nodeIds) +``` + +### 6.2 注册队列 + +参数 + ++ from 调用该接口的账户地址 ++ queueName 队列名称 ++ routingkeys 想要订阅的消息类型 ++ isVerbose 推送区块时是否推送交易列表,true表示是 ++ nodeIds 说明请求向哪些节点发送 + +```java +Request registerQueue(String from, String queueName, List routingkeys, Boolean isVerbose, int... nodeIds); +``` + +### 6.3 注销队列 + +参数 + ++ from 调用该接口的账户地址 ++ queueName 队列名称 ++ exchangerName exchanger 名称 ++ nodeIds 说明请求向哪些节点发送 + +```java +Request unRegisterQueue(String from, String queueName, String exchangerName, int... nodeIds); +``` + +### 6.4 获取所有队列名称 + +参数 + ++ nodeIds 说明请求向哪些节点发送 + +```java +Request getAllQueueNames(int... nodeIds); +``` + +### 6.5 获取所有exchanger名称 + +参数 + ++ nodeIds 说明请求向哪些节点发送 + +```java +Request getExchangerName(int... nodeIds); +``` + +### 6.6 删除exchanger + +参数 + ++ exchangerName exchanger名称 ++ nodeIds 说明请求向哪些节点发送 + +```java +Request deleteExchanger(String exchangerName, int... nodeIds); ``` \ No newline at end of file diff --git a/src/main/java/cn/hyperchain/sdk/request/MQRequest.java b/src/main/java/cn/hyperchain/sdk/request/MQRequest.java new file mode 100644 index 00000000..bb93b111 --- /dev/null +++ b/src/main/java/cn/hyperchain/sdk/request/MQRequest.java @@ -0,0 +1,19 @@ +package cn.hyperchain.sdk.request; + +import cn.hyperchain.sdk.exception.RequestException; +import cn.hyperchain.sdk.provider.ProviderManager; +import cn.hyperchain.sdk.response.MQResponse; +import cn.hyperchain.sdk.response.Response; + +public class MQRequest extends Request { + public MQRequest(String method, ProviderManager providerManager, Class clazz, int... nodeIds) { + super(method, providerManager, clazz, nodeIds); + } + + @Override + public T send() throws RequestException { + T response = super.send(); + + return response; + } +} diff --git a/src/main/java/cn/hyperchain/sdk/response/MQResponse.java b/src/main/java/cn/hyperchain/sdk/response/MQResponse.java new file mode 100644 index 00000000..49e29c0e --- /dev/null +++ b/src/main/java/cn/hyperchain/sdk/response/MQResponse.java @@ -0,0 +1,47 @@ +package cn.hyperchain.sdk.response; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.annotations.Expose; + +import java.util.ArrayList; +import java.util.List; + +public class MQResponse extends Response { + @Expose + private JsonElement result; + + /** + * return list of queue names. + * @return list of queue names + */ + public List getQueueNames() { + List queue = new ArrayList<>(); + Gson gson = new Gson(); + if (result.isJsonArray()) { + JsonArray jsonArray = result.getAsJsonArray(); + for (JsonElement element: jsonArray) { + String name = gson.fromJson(element, String.class); + queue.add(name); + } + } + + return queue; + } + + public String getExchanger() { + return result.getAsString(); + } + + @Override + public String toString() { + return "MQResponse{" + + "jsonrpc='" + jsonrpc + '\'' + + ", id='" + id + '\'' + + ", code=" + code + + ", message='" + message + '\'' + + ", result" + result.toString() + '\'' + + '}'; + } +} diff --git a/src/main/java/cn/hyperchain/sdk/service/MQService.java b/src/main/java/cn/hyperchain/sdk/service/MQService.java index 55461453..5d43c15f 100644 --- a/src/main/java/cn/hyperchain/sdk/service/MQService.java +++ b/src/main/java/cn/hyperchain/sdk/service/MQService.java @@ -1,4 +1,22 @@ package cn.hyperchain.sdk.service; +import cn.hyperchain.sdk.request.Request; +import cn.hyperchain.sdk.response.MQResponse; + +import java.util.List; + public interface MQService { + + + Request registerQueue(String from, String queueName, List routingkeys, Boolean isVerbose, int... nodeIds); + + Request unRegisterQueue(String from, String queueName, String exchangerName, int... nodeIds); + + Request getAllQueueNames(int... nodeIds); + + Request informNormal(int... nodeIds); + + Request getExchangerName(int... nodeIds); + + Request deleteExchanger(String exchangerName, int... nodeIds); } diff --git a/src/main/java/cn/hyperchain/sdk/service/ServiceManager.java b/src/main/java/cn/hyperchain/sdk/service/ServiceManager.java index dcc6d38c..14e43e71 100644 --- a/src/main/java/cn/hyperchain/sdk/service/ServiceManager.java +++ b/src/main/java/cn/hyperchain/sdk/service/ServiceManager.java @@ -3,6 +3,7 @@ import cn.hyperchain.sdk.provider.ProviderManager; import cn.hyperchain.sdk.service.impl.AccountServiceImpl; import cn.hyperchain.sdk.service.impl.ContractServiceImpl; +import cn.hyperchain.sdk.service.impl.MQServiceImpl; import cn.hyperchain.sdk.service.impl.NodeServiceImpl; /** @@ -23,4 +24,8 @@ public static AccountService getAccountService(ProviderManager providerManager) public static NodeService getNodeService(ProviderManager providerManager) { return new NodeServiceImpl(providerManager); } + + public static MQService getMQService(ProviderManager providerManager) { + return new MQServiceImpl(providerManager); + } } diff --git a/src/main/java/cn/hyperchain/sdk/service/impl/MQServiceImpl.java b/src/main/java/cn/hyperchain/sdk/service/impl/MQServiceImpl.java new file mode 100644 index 00000000..d460affb --- /dev/null +++ b/src/main/java/cn/hyperchain/sdk/service/impl/MQServiceImpl.java @@ -0,0 +1,110 @@ +package cn.hyperchain.sdk.service.impl; + +import cn.hyperchain.sdk.provider.ProviderManager; +import cn.hyperchain.sdk.request.MQRequest; +import cn.hyperchain.sdk.request.Request; +import cn.hyperchain.sdk.response.MQResponse; +import cn.hyperchain.sdk.service.MQService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MQServiceImpl implements MQService { + private ProviderManager providerManager; + private static final String MQ_PREFIX = "mq_"; + + public MQServiceImpl(ProviderManager providerManager) { + this.providerManager = providerManager; + } + + + /** + * register mq queue. + * @param from account address + * @param queueName queue name that you want to name it + * @param routingkeys what message type you want to receive + * @param isVerbose whether need to push transaction list when push block + * @param nodeIds specific ids + * @return {@link Request} of {@link MQResponse} + */ + @Override + public Request registerQueue(String from, String queueName, List routingkeys, Boolean isVerbose, int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest(MQ_PREFIX + "register", providerManager, MQResponse.class, nodeIds); + + Map params = new HashMap<>(); + params.put("from", from); + params.put("queueName", queueName); + params.put("routingkeys", routingkeys); + params.put("isVerbose", false); + mqResponseMQRequest.addParams(params); + + return mqResponseMQRequest; + + } + + /** + * get all queue names. + * @param nodeIds specific ids + * @return {@link Request} of {@link MQResponse} + */ + @Override + public Request getAllQueueNames(int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest<>(MQ_PREFIX + "getAllQueueNames", providerManager, MQResponse.class, nodeIds); + return mqResponseMQRequest; + } + + /** + * inform mq server of starting work. + * @param nodeIds specific ids + * @return {@link Request} of {@link MQResponse} + */ + @Override + public Request informNormal(int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest<>(MQ_PREFIX + "informNormal", providerManager, MQResponse.class, nodeIds); + mqResponseMQRequest.addParams(""); + return mqResponseMQRequest; + } + + /** + * unregister mq queue. + * @param queueName queue name + * @param exchangerName exchanger name + * @param from account address + * @param nodeIds specific ids + * @return {@link Request} of {@link Request} + */ + @Override + public Request unRegisterQueue(String from, String queueName, String exchangerName, int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest<>(MQ_PREFIX + "unRegister", providerManager, MQResponse.class, nodeIds); + mqResponseMQRequest.addParams(queueName); + mqResponseMQRequest.addParams(exchangerName); + mqResponseMQRequest.addParams(from); + mqResponseMQRequest.addParams(""); + return mqResponseMQRequest; + } + + /** + * get exchanger names. + * @param nodeIds specific ids + * @return {@link Request} of {@link MQResponse} + */ + @Override + public Request getExchangerName(int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest<>(MQ_PREFIX + "getExchangerName", providerManager, MQResponse.class, nodeIds); + return mqResponseMQRequest; + } + + /** + * delete exchanger. + * @param exchangerName the name of exchange that you want to delete + * @param nodeIds specific ids + * @return {@link Request} of {@link MQResponse} + */ + @Override + public Request deleteExchanger(String exchangerName, int... nodeIds) { + MQRequest mqResponseMQRequest = new MQRequest<>(MQ_PREFIX + "deleteExchanger", providerManager, MQResponse.class, nodeIds); + mqResponseMQRequest.addParams(exchangerName); + return mqResponseMQRequest; + } +} diff --git a/src/test/java/cn/hyperchain/sdk/HVMTest.java b/src/test/java/cn/hyperchain/sdk/HVMTest.java index 433f5a46..62cd61d9 100644 --- a/src/test/java/cn/hyperchain/sdk/HVMTest.java +++ b/src/test/java/cn/hyperchain/sdk/HVMTest.java @@ -10,7 +10,6 @@ import cn.hyperchain.sdk.hvm.StudentInvoke; import cn.hyperchain.sdk.provider.DefaultHttpProvider; import cn.hyperchain.sdk.provider.ProviderManager; -import cn.hyperchain.sdk.request.Request; import cn.hyperchain.sdk.response.ReceiptResponse; import cn.hyperchain.sdk.response.TxHashResponse; import cn.hyperchain.sdk.service.AccountService; diff --git a/src/test/java/cn/hyperchain/sdk/service/MQServiceTest.java b/src/test/java/cn/hyperchain/sdk/service/MQServiceTest.java new file mode 100644 index 00000000..852ec322 --- /dev/null +++ b/src/test/java/cn/hyperchain/sdk/service/MQServiceTest.java @@ -0,0 +1,86 @@ +package cn.hyperchain.sdk.service; + +import cn.hyperchain.sdk.exception.RequestException; +import cn.hyperchain.sdk.provider.DefaultHttpProvider; +import cn.hyperchain.sdk.provider.HttpProvider; +import cn.hyperchain.sdk.provider.ProviderManager; +import cn.hyperchain.sdk.request.Request; +import cn.hyperchain.sdk.response.MQResponse; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class MQServiceTest { + String url = "localhost:8081"; + HttpProvider provider = new DefaultHttpProvider.Builder().setUrl(url).build(); + ProviderManager providerManager = new ProviderManager.Builder().providers(provider).build(); + MQService mqService = ServiceManager.getMQService(providerManager); + String exchanger = null; + String from = "0x2CC762775FC1AA7486AA2FCF0D7885D4EEE4DA2"; + + @Before + public void init() throws RequestException { + Request request = mqService.informNormal(); + request.send(); + + Request exchangerName = mqService.getExchangerName(); + exchanger = exchangerName.send().getExchanger(); + } + + @Test + public void testAllQueueNames() throws RequestException { + Request allQueueNames = mqService.getAllQueueNames(); + MQResponse mqResponse = allQueueNames.send(); + System.out.println(mqResponse.getQueueNames()); + } + + @Test + public void testRegisterQueue() throws RequestException { + ArrayList array = new ArrayList(); + array.add("MQBlock"); + array.add("MQLog"); + array.add("MQException"); + String queueName = "mqtest"; + boolean isVerbose = false; + + Request registerQueue = mqService.registerQueue(from, queueName, array, isVerbose); + MQResponse mqResponse = registerQueue.send(); + System.out.println(mqResponse); + } + + @Test + public void testUnRegisterQueue() throws RequestException { + List queues = mqService.getAllQueueNames().send().getQueueNames(); + if (queues.isEmpty()) { + return ; + } + String queueName = queues.get(0); + + Request unRegisterQueue = mqService.unRegisterQueue(from, queueName, exchanger); + MQResponse mqResponse = unRegisterQueue.send(); + System.out.println(mqResponse); + } + + @Test + public void testDeleteExchanger() throws RequestException { + List queueNames = mqService.getAllQueueNames().send().getQueueNames(); + for (String queue: queueNames) { + mqService.unRegisterQueue(from, queue, exchanger).send(); + } + Request deleteExchanger = mqService.deleteExchanger(exchanger); + MQResponse mqResponse = deleteExchanger.send(); + System.out.println(mqResponse); + } + + @Test + public void testGetExchangerName() throws RequestException { + Request exchangerName = mqService.getExchangerName(); + MQResponse mqResponse = exchangerName.send(); + System.out.println(mqResponse.getExchanger()); + + mqService.informNormal().send(); + exchanger = mqService.getExchangerName().send().getExchanger(); + } +}