# YJS SDK
## YJS Build-in API

### 内置对象 Global


### 内置对象 requester
该内置对象在export function里面会有值，仅当合约调用签名验证通过。


### 执行合约  executeContract

参数：

``` bash
action:executeContract; 
contractID:合约的id或名称均可；
operation:调用合约的方法名；
arg: 参数；格式为JSON字符串，有action与arg两个字段。
```
	
可选参数：

```bash
requestID:字符串类型，自行生成，用于查询hash
```

使用示例：

```javascript

 function testExecutorContract(arg){
    var ret = JSON.parse(executeContract("ElemeProvider","queryDB",arg));
    if (ret.status == "Success"){
      return JSON.parse(ret.result);
    }else return null;
  }
```
### 订阅事件主题 subscribe

参数

``` bash
contractID：字符串类型 合约id或名称均可。
event：字符串类型
handler：方法名，该方法必须接受Event（内含字段topic和content）类型的唯一变量为参数；可以不是export方法
```

使用示例：

```javascript
export function init(arg) {
    YancloudUtil.subscribe("topic", handler);
    print("Handler: " + handler);
}

function handler(e) {
    print("topic: " + e.topic);
    print("content: " + e.content);
}

```

### 发布事件 pubEvent

参数

``` bash
topic：字符串类型，发布的事件主题
content：字符串类型，发布的事件内容
```
使用示例：

```javascript
export function pub1(arg) {
    YancloudUtil.pubEvent("topic", arg);
    return "done";
}
```

也可以在合约开头声明事件，则事件名即为事件主题，此时可直接使用事件作为方法名发布事件

```javascript
event topic;
export function pub2(arg) {
    topic(arg);
    return "done";
}
```

该写法与上面的`pub1`等价。

### 发布带语义事件 pubEventConstraint

参数

``` bash
topic：字符串类型，发布的事件主题
content：字符串类型，发布的事件内容
semantics：枚举类型，作为字符串输入，事件语义
```

事件语义参数
+ AT_LEAST_ONCE：至少一次，默认语义
+ AT_MOST_ONCE：至多一次
+ ONLY_ONCE：只有一次

使用示例：

```javascript
export function pub1(arg) {
    YancloudUtil.pubEventConstraint("topic", arg, "AT_MOST_ONCE");
    return "done";
}
```

也可以在合约开头声明事件，则事件名即为事件主题，此时可直接使用事件作为方法名按声明的语义发布事件

```javascript
event AT_MOST_ONCE topic;
export function pub2(arg) {
    topic(arg);
    return "done";
}
```

该写法与上面的`pub1`等价。

事先声明的事件无论是否声明语义，都可以用后缀s作为方法名的方式调用，发布任意语义的事件：

```javascript
event topic;
export function pub3(arg) {
    topics(arg, "AT_MOST_ONCE");
    return "done";
}
```

该写法与上面的`pub1, pub2`等价。

*不带事件语义声明事件时，语义默认为至少一次（AT_LEAST_ONCE）。*

### 访问资源文件
 
通过Global.Resources去加载ypk内部的资源文件。
 
#### loadAsInputStream

参数：
 
 ```bash     
 path：字符串类型 需要加载文件的地址
 ```
 使用示例：
 
 ```javascript
 var file = Global.Resources.loadAsInputStream("/deleteit.txt");
 ```
 
#### loadAsScanner 

参数：
 
 ```bash    
 path：字符串类型 需要加载文件的地址
 ```
 
 使用示例：
 
 ```javascript
 var scanner = Global.Resources.loadAsScanner("/local.txt");
 ```
### YancloudUtil

提供了一些内置的工具方法。

#### getKeyPair

参数：
```
无
```

使用示例：

```
var keyPair = YancloudUtil.getKeyPair();
//该类型为SM2KeyPair类型，
print(keyPair.getPublicKeyStr());
print(keyPair.getPrivateKeyStr());
print(keyPair.toJson());
```
 
 
## YJS Build-in Annotation

### @Access

设置合约的调用是否需要签名，这里分为两种，需签名和无签名。
其中，"verified"表示需要签名。其他则表示无需签名。

```
@Access("verified")
export function easy(arg){
    return "true";
}
```

### @LogType

LogType注解通过参数的方式声明合约或函数的需要记录的日志类型。

其中，Arg表示日志中记录合约执行的参数；Result表示记录合约执行的返回结果；Branch表示记录合约执行分支。

例如 ，通过如下LogType注解来声明函数

```
@LogType("Arg","Result","Branch")
export function easy(arg){
    Global.a = "a";
    Global.b = "b";
    if(arg > 0)
        return Global.a;
    else
        return Global.b;
}
```

### @LogLocation

该注解可以修饰`contract`或`function`。
设置日志存储的位置。参数中指定为“dataware”则存储在账本和本地，如果没有指定为“dataware”则仅存储在本地。
例如，通过如下LogLocation设置存储位置。

在BaaS平台中，可以指定账本名称，BaaS平台默认账本为default,使用
`@LogLocation("bdledger:default")`。如想保存到自定义的账本，比如，"abc"账本，就使用
`@LogLocation("bdledger:abc")`

```
@LogLocation("dataware")
export function easy(arg){
    Global.a = "a";
}
```


### @Permission
该注解只能修饰`contract`
设置合约中调用的工具类的权限，包括File、Http、MySQL、MongoDB、RocksDB等工具类。如果合约中用到了以上工具类，需要在注解中添加对应的授权字段，默认只有YJS自带的YancloudUtil;如果没有添加则会抛出"未授权工具类"的异常。
这6种工具类的详细说明在本小节后续中有说明。

```
@Permission("Http","File")
contract HttpPermission {
    export function main(args){
        var http=HttpUtil.httpGet(args);
        var dir="adf/adfas/";
        var file=FileUtil.getDir(dir);
        return YancloudUtil.currentTimeMillis();
    }
}
```

### @Description
该注解可以修饰`contract`或`function`。
传入合约及函数的简介，可用于生成说明文档中关于exported函数的介绍。

```
@Description("返回数据条目，无需参数")
export function count(args){
    var  sql = "select count(*) from data;";
    var conn = getConn();
    var statement = conn.createStatement();
    var resultSet = statement.executeQuery(sql);
    var c = {};
    resultSet.next();
    c.count = resultSet.getLong(1);
    return JSON.stringify(c);
}
```

### @Param
该注解可以修饰`function`。
提供调用函数的参数示例，也为生成说明文档中的返回结果提供默认参数。
```
@Param({"offset":0,"count":100})
export function get(args){
    var offset = args.offset;
    var count = args.count;
    ...
}
```
### @MockTemplate
该注解可以修饰`function`。
提供函数的返回模拟数据模板,用于描述返回值的格式.若加此注解在debug方式调用时，返回按照此格式生成的模拟数据。


####支持的字段类型
```
@integer 整数
@string  字符串
@boolean 布尔值
@date @time @datatime 
@word 单词  @cword 中文单词
@first @last 英文姓，名
@cfirst @clast @cname 中文姓，名，全名
@url @domin @ip @email 
@region @province @city @county 地区，省，市，县
……
详细格式可以参考http://mockjs.com/examples.html
```
####注意：模板的格式为{‘result’:模板}
```json
//返回一个对象包含如下字段
@MockTemplate({'result':{'id':'@integer','email':'@email','password':'@string','name':'@name'}})
//返回
{"password":"3ZLc","name":"William Young","id":36097783842688,"email":"d.fuunwe@gqnr.to"}"


//返回元素个数为1-5个之间的一个数组，数组的每个元素都是上述格式的一个对象
{'result|1-5':[{'id':'@integer','email':'@email','password':'@string','name':'@name'}]}
//返回
[
  {"password":"dO]wW","name":"Jeffrey Lopez","id":1783453207480410,"email":"a.ckokgxrga@hgiesugi.bb"},
  {"password":"BQYRL","name":"Brian Moore","id":4310212972071102,"email":"k.lbpxocydrh@msgnjtox.na"},
  {"password":"Gw1","name":"Susan Jackson","id":7766580783668916,"email":"h.zjgusl@htce.cr"}
]
```
```
@MockTemplate({'result':{'id':'@integer','email':'@email','password':'@string','name':'@name'}})
export function count(args){
    var  sql = "select count(*) from data;";
    var conn = getConn();
    var statement = conn.createStatement();
    var resultSet = statement.executeQuery(sql);
    var c = {};
    resultSet.next();
    c.count = resultSet.getLong(1);
    return JSON.stringify(c);
}
```
### @Result
该注解可以修饰`function`。
提供函数的返回结果示例，若加此注解则生成说明文档时将直接返回此结果而不使用默认参数调用函数。
```
@Result(666)
export function count(args){
    var  sql = "select count(*) from data;";
    var conn = getConn();
    var statement = conn.createStatement();
    var resultSet = statement.executeQuery(sql);
    var c = {};
    resultSet.next();
    c.count = resultSet.getLong(1);
    return JSON.stringify(c);
}
```
### @Cost
该注解可以修饰`function`。
提供函数的cpu计量功能。
```
@Cost({"countGas":true})
export function ....


```

## IO工具类

### 概览

|IO工具类名称|说明|
|---|---|
| [FileUtil](./YJSAPI.html#fileutil) | 文件操作相关的类 |
| [LedgerUtil](./YJSAPI.html#ledgerutil) | 账本操作相关的类 |
| [HttpUtil](./YJSAPI.html#httputil) | Http接口相关的类 |
| [DOIPUtil](./YJSAPI.html#doiputil) | DoIP相关的类 |
| [MySQLUtil](./YJSAPI.html#mysqlutil) | 连接mysql数据库 |
| [MongoDBUtil](./YJSAPI.html#mongodbutil) | MongoDB连接相关的类 |
| [RocksDBUtil](./YJSAPI.html#rocksdbutil) | RocksDB（基于本地文件的k-v数据库） |
| [BDWareTimeSeriesDBUtil](./YJSAPI.html#BDWareTimeSeriesDBUtil) | 基于本地文件的时间序列数据库 |
 

### FileUtil
可以使用@Permission("File")来引入FileUtil对象。

```
@Permission("File")
contract FileSample {
...
}
```

该对象支持以下方法：

#### copyTo

可以复制文件和目录。第一个参数是source，第二个参数是destination。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | src | 类型为String |
| 2 | dest | 类型为String |

##### 使用示例

```javascript
var ret = FileUtil.copyTo("./source.txt","./dest.txt");
```

#### getContent

获取文件的文本内容，当文件不存在时，返回```undefined```。

##### 参数

| 序号 | 参数 | 说明 |
| --- | --- | --- |
| 1 | path | 类型为String |

##### 使用示例

```javascript
var ret = FileUtil.getContent("./source.txt");
```
#### getDir

获取文件所在的文件夹名，输入参数为字符串。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | path | 类型为String |

##### 使用示例
```javascript
var ret = FileUtil.getDir("./parent/src.txt");
// ret 为 "./parent/";
```

#### getFileName

获取文件名。输入参数为字符串。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | path | 类型为String |

##### 使用示例

```javascript
var ret = FileUtil.getFileName("./parent/src.txt");
// ret 为 "src.txt"
```


#### openFileAsPrinter

以PrintStream的形式打开文件。
返回结果是```java.io.PrintStream```类型。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | path | 文件名，类型为String |
| 2 | isAppend| 类型为boolean，表示是否往文件末尾添加 |

##### 使用示例

```javascript
var ret = FileUtil.openFileAsPrinter("./parent/src.txt",true);
ret.println("hello");
ret.close();
```

### LedgerUtil

可以使用@Permission("Ledger")来引入LedgerUtil对象。
```
@Permission("Ledger")
contract LedgerExample{
...
}
```

#### getClient

获取一个连接客户端，一个参数，为对象类型。
返回结果为LedgerClient类型，用于后续的查询账本等操作。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | address | 包含ip和端口两个字段  |

##### 使用示例

```javascript
var address = {};
address.ip = "127.0.0.1";
address.port = 18091;
var ledgerClient = LedgerUtil.getClient(address);
```

#### queryByHash

根据Hash查询Transaction。
返回结果为对象，包含from、to、type和data四个字段，均为String类型。
其中data为按utf-8编码解析字节数组，如果存证时用的不是utf8编码，可能返回乱码。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | client | 通过getClient方法获得的对象 |
| 2 | info | 对象类型，有两个字段ledger和hash，均为字符串类型  |

##### 使用示例

```javascript
// ... ledgerClient = LedgerUtil.getClient(...);
var info = {};
info.ledger = "bdcontract";
info.hash = "4d3b75750835092a50085127702669615b602e53";
var ret = LedgerUtil.queryByHash(ledgerClient,info);
print(ret.from);
print(ret.to);
print(ret.type);
print(ret.data);
```

#### sendTransaction

存证数据。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | client | 通过getClient方法获得的对象 |
| 2 | info | 对象类型，有from\to\data三个字段，均为String类型 |

##### 使用示例

```javascript
// ... ledgerClient = LedgerUtil.getClient(...);
var info = {};
info.ledger = "bdcontract";
info.from = "b60e8dd61c5d32be8058bb8eb970870f07233155";
info.to = "b60e8dd61c5d32be8058bb8eb970870f07233155";
info.data = "hello world";
var ret = LedgerUtil.sendTransaction(ledgerClient,info);
//ret为存证的哈希值
print(ret);
```

### HttpUtil

可以使用@Permission("Http")来引入HttpUtil对象。
```
@Permission("Http")
contract HttpExample{
...
}
```

#### createAPIGate

配合手机的元邦使用，当手机安装元邦且安装了API 接口后，可成为数据来源。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | ip | 字符串类型，ip，端口默认为6161 |

##### 使用示例

```javascript
var ret = HttpUtil.createAPIGate("192.168.4.4");
ret.get("com.tencent.mm","sendMsg","msg");
print(ret);
```

#### createAPIGate

配合手机的元邦使用，当手机安装元邦且安装了API 接口后，可成为数据来源。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | ip | 字符串类型，ip|
| 2 | port | 字符串类型，端口 |

##### 使用示例

```javascript
var ret = HttpUtil.createAPIGate("192.168.4.4", "6161");
ret.get("com.tencent.mm","sendMsg","msg");
print(ret);
```

#### get

发起Http的get请求。
返回结果为对象类型，包含response和responseCode两个字段。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | url | 字符串，表示url类型 |

##### 使用示例

```javascript
var ret = HttpUtil.get("https://www.baidu.com");
print(ret.responseCode);
print(ret.response);
```

#### post
发起Http的post请求。
返回结果为对象类型，包含response和responseCode两个字段。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | args | 对象类型，有url，headers和data三个字段。其中，args.headers为对象类型。|

##### 使用示例

```javascript
var req = {};
req.url = "https://www.baidu.com";
req.data = "hello";
req.header = {};
req.header.Accept = "application/json";
req.header["Content-Type"] = "application/json";
var ret = HttpUtil.post(req);
print(ret.resposeCode);
print(ret.response);
```

### DOIPUtil

可以使用@Permission("DOIP")来引入DOIPUtil对象。
```
@Permission("DOIP")
contract DOIPExample{
  ...
}
```

#### call
调用一个DO

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型, 目标DO标识|
| 2 | arg1 | 字符串类型, 输入参数字符串|

##### 使用示例

```javascript
var ret = DOIPUtil.call("86.5000.470/do.hello","inputString");
```
#### create
向一个Repository创建一个字符串类型DO

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型, 目标Repo标识|
| 2 | arg1 | 对象类型,包括doID,doBody字段|

##### 使用示例

```javascript
var digitalObject = JSON.parse("{\"doID\":\"86.5000.470/do.hello\",\"doBody\":\"hello world\"}");
var ret = DOIPUtil.create("86.5000.470/repo.localTcpRepo",digitalObject);
```
#### delete
从一个Repository中删除DO

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 目标DO标识|
| 2 | arg1 | 字符串类型 目标Repo标识|

##### 使用示例

```javascript
var ret = DOIPUtil.delete("86.5000.470/do.hello","86.5000.470/repo.localTcpRepo");
```
#### hello
获取目标Repository的DOIP服务信息

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 目标Repo标识|

##### 使用示例

```javascript
var ret = DOIPUtil.hello("86.5000.470/repo.localTcpRepo");
```
#### listOperation
获取目标DO支持的DOIP操作

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 目标DO标识|

##### 使用示例

```javascript
var ret = DOIPUtil.listOperation("86.5000.470/do.hello");
```
#### register
向LHS注册一个DO，返回分配的标识

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 DO所在Repo标识|
| 2 | arg1 | 字符串类型 DO格式描述字符串|

##### 使用示例

```javascript
var ret = DOIPUtil.register("86.5000.470/repo.localTcpRepo","String");
```
#### reregister
修改LHS中DO的注册信息

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 目标DO标识|
| 2 | arg1 | 字符串类型 DO所在Repo标识|
| 3 | arg2 | 字符串类型 DO格式描述字符串|

##### 使用示例

```javascript
var ret = DOIPUtil.reregister("86.5000.470/do.hello","86.5000.470/repo.localTcpRepo","String");
```
#### retrieve
获取一个DO

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 目标DO标识|

##### 使用示例

```javascript
var ret = DOIPUtil.retrieve("86.5000.470/do.hello");
```
### test
测试DOIPUtils是否可用
##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | 字符串类型 任意字符串|

##### 使用示例

```javascript
var ret = DOIPUtil.test("hello");
```
#### update
更新目标DO

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 |   JS对象,包括doID,doBody字段|

##### 使用示例

```javascript
var digitalObject = JSON.parse("{\"doID\":\"86.5000.470/do.hello\",\"doBody\":\"hello world\"}");
var ret = DOIPUtil.update(digitalObject);
```



### SQLUtil

可以使用@Permission("SQL")来引入SQLUtil对象。
可支持MySQL/PostgreSQL/Oracle/GuassDB200等SQL数据库。
需要将对应的jdbc的jar上传到项目中。
例如，要使用mysql，可上传mysql-connector-java-8.0.24.jar

```
@Permission("SQL")
oracle MySQLExample{
...
}
```

#### initDriver

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | driverClass | 字符串类型 |

##### 使用示例

```javascript
    //使用mysql
    SQLUtil.initDriver("com.mysql.cj.jdbc.Driver");
    //使用postgresql
    SQLUtil.initDriver("org.postgresql.Driver");
    //使用oracle
    SQLUtil.initDriver("oracle.jdbc.OracleDriver");
```

#### getConnection

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | URL | 字符串类型，jdbc连接 |
| 2 | usrName | 字符串类型，用户名 |
| 3 | pwd | 字符串类型，密码 |


##### 使用示例

```javascript
var url = "jdbc:mysql://xx.xx.xx:port/tableName";
var usrName = "xxx";
var pwd = "xxx";
//配置好用户名和密码，url格式为ip或域名+端口，中间以”:”隔开。
var conn = SQLUtil.getConnection(url,usrName,pwd);
//获取数据库连接
var sql = "select * from newele.data";
//创建查询语句
var statement = conn.createStatement();
var resultSet = statement.executeQuery(sql);
var waimailist  = [];
//解析查询结果
var meta = resultSet.getMetaData();
for (;resultSet.next();){
  var line = {};
  for (var j=1;j<=meta.getColumnCount();j++){
    line[meta.getColumnName(j)] = resultSet.getString(j);
  }
	waimailist.push(line);
}
```

其中，getConnection方法返回的对象通过反射机制绑定到了Java的一个java.util.Connection对象。因此，可以查看：
<https://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html>
以了解如何进行Mysql数据库操作。


### MongoDBUtil

可以使用@Permission("MongoDB")来引入MongoDBUtil对象。
```
@Permission("MongoDB")
contract MongoDBExample{
...
}
```

#### getConnection


##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | URL | 字符串类型 数据库的URL |
| 2 | port | 整数类型 端口号 |
| 3 | dbName | 字符串类型 数据库的名称 |
| 4 | usrName | 字符串类型 数据库的用户名 |
| 5 | pwd | 字符串类型 数据库的密码 |

	
##### 使用示例

**注意：port为整型，其他参数为String类型**

```javascript
var client = MongoDBUtil.getConnection(url,port,dbName,usrName,pwd);
//获取数据库对象
var db = client.getDatabase("yancloud");
var collection = db.getCollection("containers");
var iter = collection.find().iterator();
var ret ="";
for (;iter.hasNext();){
	ret+=iter.next().toJson();
	ret+="\n";
}
```

其中，getMongoDBClient对象通过反射机制绑定到了Java的一个com.mongodb.MongoClient对象。因此，可以查看：
<https://mongodb.github.io/mongo-java-driver/3.4/javadoc/com/mongodb/MongoClient.html>

以了解该对象的更多方法和使用方式。

### RocksDBUtil

使用@Permission("RocksDB")来引入RocksDBUtil对象。

```
@Permission("RocksDB")
contract RocksDBSample {
...
}
```

#### loadDB

通过loadDB来加载一个RocksDB数据库。
加载后，可进行get/delete/put等操作。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | path | 字符串类型 数据库部署的路径 |
| 2 | readOnly | 布尔类型 数据库只读 |

##### 使用示例

```
@Permission("RocksDB")
@Description("这是个使用RocksDB的参考代码")
contract RocksDBSample{
  function onCreate(){
    Global.rocksdb = RocksDBUtil.loadDB("./dbdir/","false");
  }
  @Description("示例参数: {\"key\":\"abc\",\"value\":\"def\"}")
  export function put(arg){
    arg = JSON.parse(arg);
    Global.rocksdb.put(arg.key,arg.value);
    return "success";
  }
  @Description("示例参数: \"abc\"}")
  export function get(arg){
    return Global.rocksdb.get(arg);
    return "failed";
  }
  @Description("示例参数: \"abc\"")
  export function deleteKey(arg){
    return Global.rocksdb.delete(arg);
  }
  @Description("遍历KV库，无需参数")
  export function iter(arg){
    var iter = Global.rocksdb.newIterator();
    var obj = undefined;
    var ret = {
    };
    for (iter.seekToFirst();(obj=Global.rocksdb.getNext(iter))!=undefined;){
      ret[obj.key]=obj.value;
    }
    return JSON.stringify(ret)
  }
}
```

### BDWareTimeSeriesDBUtil

使用示例

```
@Permission("BDWareTimeSeriesDB")
contract BDWareTimeDBExample{
  function onCreate(arg){
    Global.dbutil = BDWareTimeSeriesDBUtil.getConnection();
  }

  export function put(arg){
    //第一个参数为表名，第二个参数为要放的value，时间戳自动打。
    Global.dbutil.put("defaultTable",arg);
    return "success";
  }
  @Param
  export function getCount(arg){
    return Global.dbutil.getCount("defaultTable");
  }
  @Param(1617254937373)
  export function queryByStartTime(arg){
    var startDate = java.lang.Long.valueOf(arg);
    //查询从开始时刻startDate到最新的数据
    var list = Global.dbutil.query("defaultTable",startDate);
    var ret=[];
    print("DBUtil"+Global.dbutil+" list:"+list+" list.size"+list.size());
    var i=0;
    for (i=0;i<list.size();i++){
      print(i+"-->"+list.get(i));
      ret.push(list.get(i));
    }
    return ret;
  }
  
  @Description("示例参数: {\"offset\":1,\"len\":1}")
  @Param({"offset":1,"len":1})
  export function queryByOffset(arg){
    var offsetLen = JSON.parse(arg);
    //可配合getCount使用，查询第offset至offset+len条数据
    var list = Global.dbutil.queryByOffset("defaultTable",offsetLen.offset,offsetLen.len);
    var ret=[];
    print("DBUtil"+Global.dbutil+" list:"+list+" list.size"+list.size());
    var i=0;
    for (i=0;i<list.size();i++){
      print(i+"-->"+list.get(i));
      ret.push(list.get(i));
    }
    return ret;
  }
}

```

		
## 加解密工具类


### SM2
可以使用@Permission("SM2")来引入SM2Util对象。

```
@Permission("SM2")
contract SM2Sample {
...
}
```

#### generateKeyPair
生成公私钥。

##### 参数
无参数。
		
##### 使用示例

```javascript
var ret = SM2Util.generateKeyPair();
print(ret.publicKey);
print(ret.privateKey);
return JSON.stringify(ret);
```

#### sign

签名。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | content | 字符串类型 要进行签名的内容 |
| 2 | keyPair | sm2 |


##### 使用示例

```
var keypair = SM2Util.generateKeyPair();
var ret = SM2Util.sign("Hello",keypair);
print(ret.status);
//如果status是success
print(ret.signature);
//如果status是failed
print(ret.message);
```

#### verify

验签。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | content | 字符串类型 待验签的内容 |
| 2 | signature | 字符串类型 签名 |
| 3 | publicKey | 字符串类型 公钥 |

##### 使用示例

```javascript
var ret = SM2Util.verify("Hello","....签名","...公钥");
// 验证通过时，result为true，status为success
// 失败时，result为failed，status为failed
print(ret.status);
print(ret.result);
```

#### encrypt

sm2加密。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | content | 字符串类型 待验签的内容 |
| 3 | publicKey | 字符串类型 公钥 |

##### 使用示例

```javascript
var ret = SM2Util.encrypt("Hello","...公钥");
print(ret);
```
#### decrypt

sm2解密。

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | content | 字符串类型 待验签的内容 |
| 3 | privateKey | 字符串类型 公钥 |

##### 使用示例

```javascript
var ret = SM2Util.decrypt("Hello","...私钥");
print(ret);
```



## 多线程工具类

### AsyncUtil

可以使用@Permission("Async")来引入AsyncUtil对象。
```
@Permission("Async")
contract AsyncExample{
  export function longTimeTask(arg){
    var a = {
    };
    a.count = 100;
    AsyncUtil.postFunction(taskFun,a);
  }
  function taskFun(arg){
    Global.progress = 0;
    for (var i=0;i<arg.count;i++){
      AsyncUtil.sleep(100);
      Global.progress++;
    }
  }
  export function getProgress(arg){
    return Global.progress;
  }
}
```

#### postFunction

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | ScriptFunction |
| 2 | arg1 | 对象 |

##### 使用示例

```javascript
var ret = AsyncUtil.postFunction(a,{"a":"b"});
```
#### setInterval

##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | ScriptFunction |
| 2 | arg1 | long |
| 3 | arg2 | long |
| 4 | arg3 | 对象 |

##### 使用示例

```javascript
var ret = AsyncUtil.setInterval(a,100,1000,"abc");
```
#### setTimeOut


##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | ScriptFunction |
| 2 | arg1 | long |
| 3 | arg2 | Object |

##### 使用示例

```javascript
var ret = AsyncUtil.setTimeOut(a,100,"abc");
```
#### sleep


##### 参数

| 序号 | 参数 | 说明 |
|---|---|---|
| 1 | arg0 | long |

##### 使用示例

```javascript
var ret = AsyncUtil.sleep();
```

## ECMA5 Build-in Objects
YJS支持ECMAScript6的部分内置对象 ：

* String		<https://www.w3schools.com/js/js_strings.asp>

* Number		<https://www.w3schools.com/js/js_numbers.asp>

* Math		<https://www.w3schools.com/js/js_math.asp>

* Date		<https://www.w3schools.com/js/js_dates.asp>

* RegExp		<https://www.w3schools.com/js/js_regexp.asp>

* Error		<https://www.w3schools.com/js/js_errors.asp>

* JSON		<https://www.w3schools.com/js/js_json.asp>

## YJS应用框架

### ypk项目组成
如之前描述，ypk中可存放静态资源文件（html/css/js)，在智能合约中声明loadResource方法，可返回静态资源文件。
基于loadResource，本项目提供了一个yjs应用框架。
该框架可以将合约ypk中的(html/css/js)文件通过executeContract调用，加载至前端并展示。

### 函数约定

| 序号 | 合约函数名 | 说明 |
|---|---|---|
| 1 | needRender | 不会被调用，有该函数表示需要渲染前端 |
| 2 | getMainFrame | 无参数，返回结果为String类型，表示主页的html文件路径  |
| 3 | loadResource | 参数为String，以文本形式，返回相对路径下的静态资源文件 |

### 加载流程
前端加载的参数会解析至global.urlparam。
包括以下参数：
```
//global.urlparam对象示例
{
    "contract":"TrustedStorage0899",   //表示合约ID或是合约的名称
   
    "keys":{  //表示当前登录者的密钥对
        "privateKey":"ff38dd04710...",
        "publicKey":"04fc228..."
    },
    "nodeAddr":"022.node.internetapi.cn:21030" //节点的ip+端口
}
```

加载前会先建立与nodeAddr的websocket连接。
连接建立后，加载流程分为两步：
第一步是用当前的publickey-privatekey登录。登录过程详见`BDContract SDK` 的 `合约节点WebSocket接口`
登录之后，会获取合约的信息。
并存放于global.currentContract对象。

第二步，是根据global.currentContract对象中，是否有needRender方法，
如果有，就会进入加载前端代码的流程。
具体为1.执行executeCurrentContract("getMainFrame") 获取页面的html，append至mainDIV之后，
会解析所有`<script>`,`<link>`等标签。2.会以标签中的`fromContract`属性，去调用executeCurrentContract("loadResources")方法。
典型的yjs的loadResources方法如下。3.获取所有script会进行eval,link会当css加载。
```
//在某个yjs文件中声明。
  export function loadResource(arg){
    return Global.Resources.loadAsString(arg);
  }
```

![前端加载流程图](./_static/imgs/clientLoadProcess.png)


### 前端框架预置函数说明

前端的javascript在html中已加载了jquery(使用$.)和vue2。
为避免冲突，本版不支持再加载vue2/vue3脚本。
前端通过executeContract/executeCurrentContract与后端交互。

#### executeContract
调用某个合约的某个函数。会自动使用当前的global.sm2Key进行签名。参数说明及示例：
```javascript
executeContract(contracID,operation,arg,callback);
//其中，contractID为string类型，为被调用的合约名称/合约ID。
//operation为string类型，合约函数
//arg为string类型，表示参数
//callback为函数类型，接受返回结果的回调函数。
```

#### executeCurrentContract
执行当前合约的某个函数。会自动使用当前的global.sm2Key进行签名。参数说明及示例：
```javascript
executeContract(operation,arg,callback);
//operation为string类型，合约函数
//arg为string类型，表示参数
//callback为函数类型，接受返回结果的回调函数。
```
