merge 0.4.0

This commit is contained in:
CaiHQ 2023-03-18 15:48:45 +08:00
parent 08da9c63f0
commit d75feb3ee1
3 changed files with 205 additions and 156 deletions

View File

@ -7,9 +7,9 @@ BDContract SDK for Node.js and browsers.
`npm install @bdware/bdcontract-sdk`
```typescript
import { Client } from '@bdware/bdcontract-sdk'
import { WsClient } from '@bdware/bdcontract-sdk'
import { sm2 } from 'sm-crypto'
const client = new Client(
const client = new WsClient(
url,
(ev) => {
console.log(JSON.stringify(ev))
@ -42,7 +42,7 @@ function print(string) {
const url = 'ws://021.node.internetapi.cn:21030/SCIDE/SCExecutor'
const client = new bdcontract.Client(
const client = new bdcontract.WsClient(
url,
(ev) => {
console.log(JSON.stringify(ev))
@ -76,4 +76,4 @@ async function anotherPlace() {
// In another place, wait for login to complete
const success = await client.Loggedin()
}()
```
```

View File

@ -1,6 +1,6 @@
{
"name": "@bdware/bdcontract-sdk",
"version": "0.3.0-alpha.15",
"version": "0.4.0-beta",
"description": "BDContract SDK for Node.js and browsers",
"license": "MIT",
"keywords": [
@ -47,14 +47,5 @@
"shx": "^0.3.4",
"sucrase": "^3.25.0",
"typescript": "^4.8.2"
},
"directories": {
"lib": "lib",
"test": "test"
},
"repository": {
"type": "git",
"url": "git@gitea.internetapi.cn:bdware/bdcontract-sdk-javascript.git"
},
"author": "caihq@pku.edu.cn"
}
}

View File

@ -26,19 +26,40 @@ const genUrlParamsFromObject = (obj: Record<string, unknown>): string => {
export * from './types'
export const retryAsyncN =
(maxRetries: number) =>
async <Ret>(fn: () => Promise<Ret>) => {
let i = 0
while (true)
try {
return await fn()
} catch (e) {
if (i++ === maxRetries) {
throw e
}
}
}
export class HttpClient {
private fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>
private retryAsync: <Ret>(fn: () => Promise<Ret>) => Promise<Ret>
constructor(
private baseUrl: string,
private sm2Key: KeyPairHex,
config = {} as AxiosRequestConfig,
options: {
axios: AxiosRequestConfig
maxRetries: number
} = {
axios: {},
maxRetries: 3,
},
) {
const axiosInstance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 10000,
// headers: {'X-Custom-Header': 'foobar'}
...config,
...options.axios,
})
this.fetch = buildAxiosFetch(
@ -47,6 +68,8 @@ export class HttpClient {
return config;
} */,
)
this.retryAsync = retryAsyncN(options.maxRetries)
}
async requestWithSignature<Data>(
@ -107,7 +130,6 @@ export class HttpClient {
.catch((err) => {
// const clientRes = err as unknown as ClientResponse<Data>
// clientRes.data = (await err.text()) as Data
// console.log(err,'errerrerrerrerrerrerrerrerrerrerrerrerrerrerr')
setTimeout(() => {
reject(err)
}, 1)
@ -115,22 +137,6 @@ export class HttpClient {
})
}
async retryRequestWithSignature<Data>(retryTimes: number, path: string, init?: Partial<RequestInit>, sm2Key?: KeyPairHex ) {
let err: Error = new Error()
for (let i = 0; i<retryTimes; i++) {
try{
return await this.requestWithSignature<Data>(path, init, sm2Key)
} catch (e) {
if (i < retryTimes) {
console.log('1')
continue
}
err = e as Error
}
}
throw err
}
sign(data: string, privateKey?: string): string {
return sm2.doSignature(data, privateKey ?? this.sm2Key.privateKey, {
hash: true,
@ -141,15 +147,17 @@ export class HttpClient {
// ping
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id15
ping(): Promise<PingResponse> {
return this.requestWithSignature('/SCManager?action=ping')
return this.retryAsync(() =>
this.requestWithSignature('/SCManager?action=ping'),
)
}
// 启动合约
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id60
startContract(code: string): Promise<ClientResponse<string>> {
const params = { action: 'startContract', script: code }
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(params)}`,
return this.retryAsync(() =>
this.requestWithSignature(`/SCManager?${genUrlParamsFromObject(params)}`),
)
}
@ -158,21 +166,23 @@ export class HttpClient {
startContractByYPK(
_request: StartContractByYpkRequest,
): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'startContractByYPK',
..._request,
owner: this.sm2Key.publicKey,
aim: 'onStartContract',
signature: sm2.doSignature(
`Fixed|${_request.path}|${this.sm2Key.publicKey}`,
this.sm2Key.privateKey,
{
hash: true,
der: true,
},
),
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'startContractByYPK',
..._request,
owner: this.sm2Key.publicKey,
aim: 'onStartContract',
signature: sm2.doSignature(
`Fixed|${_request.path}|${this.sm2Key.publicKey}`,
this.sm2Key.privateKey,
{
hash: true,
der: true,
},
),
})}`,
),
)
}
@ -214,17 +224,17 @@ export class HttpClient {
),
}
}
return this.retryRequestWithSignature(
3,
`/SCManager${
method === 'GET' ? `?${genUrlParamsFromObject(request)}` : ''
}`,
{
method,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
...(method === 'POST' ? ({ body: request } as Request) : {}),
},
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager${
method === 'GET' ? `?${genUrlParamsFromObject(request)}` : ''
}`,
{
method,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
...(method === 'POST' ? ({ body: request } as Request) : {}),
},
),
)
}
@ -239,8 +249,10 @@ export class HttpClient {
id: contractID,
}
requestID && (_request.requestID = requestID!)
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
),
)
}
@ -248,7 +260,9 @@ export class HttpClient {
// 地址 http://39.104.205.122:18010/SCIDE
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id131
killAllContract(): Promise<ClientResponse<string>> {
return this.requestWithSignature('/SCManager?action=killAllContract')
return this.retryAsync(() =>
this.requestWithSignature('/SCManager?action=killAllContract'),
)
}
// 申请角色
@ -260,8 +274,10 @@ export class HttpClient {
action: 'applyNodeRole',
role,
}
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
),
)
}
@ -277,10 +293,12 @@ export class HttpClient {
isAccept,
authorizedPubKey,
}
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
undefined,
managerPair,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject(_request)}`,
undefined,
managerPair,
),
)
}
@ -332,22 +350,26 @@ export class HttpClient {
}
saveFile(_request: SaveFileRequest): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'saveFile',
..._request,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'saveFile',
..._request,
})}`,
),
)
}
listProjectPermission(
_request: ListProjectPermissionRequest,
): Promise<ClientResponse<ListProjectPermissionResponseData>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'listProjectPermission',
..._request,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'listProjectPermission',
..._request,
})}`,
),
)
}
@ -368,22 +390,31 @@ export class HttpClient {
isPrivate,
sponsorPeerID,
}
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'startContractMultiPoint',
..._request,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'startContractMultiPoint',
..._request,
})}`,
),
)
}
// 获取节点配置信息
async loadNodeConfig(): Promise<ClientResponse<LoadNodeConfigResponseData>> {
const res = await this.requestWithSignature<string>(
`/SCManager?${genUrlParamsFromObject({
action: 'loadNodeConfig',
})}`,
const res = await this.retryAsync(() =>
this.requestWithSignature<string>(
`/SCManager?${genUrlParamsFromObject({
action: 'loadNodeConfig',
})}`,
),
)
return { ...res, data: (res.status === 200 && res.data ? JSON.parse( res.data).data : {}) as LoadNodeConfigResponseData}
return {
...res,
data: (res.status === 200 && res.data
? JSON.parse(res.data).data
: {}) as LoadNodeConfigResponseData,
}
}
// 支持的key包括{licenceprojectDiryjsPathdataChaindoipConfignodeCenternodeNamemasterAddressresetNodeCenterWS}
@ -391,21 +422,25 @@ export class HttpClient {
key: string,
val: string,
): Promise<ClientResponse<boolean>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'updateConfig',
key,
val,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'updateConfig',
key,
val,
})}`,
),
)
}
// 设置pubkey为node manager
async resetNodeManager(): Promise<boolean> {
const res = await this.requestWithSignature<string>(
`/SCManager?${genUrlParamsFromObject({
action: 'resetNodeManager',
})}`,
const res = await this.retryAsync(() =>
this.requestWithSignature<string>(
`/SCManager?${genUrlParamsFromObject({
action: 'resetNodeManager',
})}`,
),
)
if (!res.data) {
return false
@ -416,38 +451,46 @@ export class HttpClient {
// 锁定某个用户的的私有目录编辑功能
lockEdit(): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'lockEdit',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'lockEdit',
})}`,
),
)
}
// 解锁某个用户的的私有目录编辑功能
unlockEdit(): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'unlockEdit',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'unlockEdit',
})}`,
),
)
}
addNode(nodePubKey: string): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'addNode',
nodePubKey,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'addNode',
nodePubKey,
})}`,
),
)
}
// 申请角色
applyRole(role: string): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'applyRole',
role,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'applyRole',
role,
})}`,
),
)
}
@ -455,29 +498,35 @@ export class HttpClient {
isAccept: boolean,
authorizedPubKey: string,
): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'authNodeManager',
isAccept,
authorizedPubKey,
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'authNodeManager',
isAccept,
authorizedPubKey,
})}`,
),
)
}
listAllUsers(): Promise<ClientResponse<ListAllUsersResponseData>> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listAllUsers',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listAllUsers',
})}`,
),
)
}
// 查看节点列表
listNodes(): Promise<ListNodesResponse> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listNodes',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listNodes',
})}`,
),
) as unknown as Promise<ListNodesResponse>
}
@ -502,30 +551,36 @@ export class HttpClient {
'04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
sign: sig,
}
return (await this.requestWithSignature('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})) as unknown as { action: string; status: string }
return (await this.retryAsync(() =>
this.requestWithSignature('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}),
)) as unknown as { action: string; status: string }
}
// 查看可信执行集群列表
listTrustUnits(): Promise<ClientResponse<{ key: string; value: string }[]>> {
return this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listTrustUnits',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`?${genUrlParamsFromObject({
action: 'listTrustUnits',
})}`,
),
)
}
// listContractProcess 查询合约实例列表
listContractProcess(): Promise<ClientResponse<string>> {
return this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'listContractProcess',
})}`,
return this.retryAsync(() =>
this.requestWithSignature(
`/SCManager?${genUrlParamsFromObject({
action: 'listContractProcess',
})}`,
),
)
}
@ -533,7 +588,7 @@ export class HttpClient {
downloadContract(
projectName: string,
isPrivate: boolean,
timestamp: number
timestamp: number,
): Promise<ClientResponse<string>> {
const _request = {
action: 'downloadContract',
@ -541,19 +596,22 @@ export class HttpClient {
isPrivate,
timestamp,
}
return this.requestWithSignature(
`/CMManager?${genUrlParamsFromObject(_request)}`)
return this.retryAsync(() =>
this.requestWithSignature(
`/CMManager?${genUrlParamsFromObject(_request)}`,
),
)
}
// 配置合约引擎节点若节点没有设置过node manager将当前key设置为node manager
async configNode(
args: ConfigNodeArgs,
): Promise<boolean> {
async configNode(args: ConfigNodeArgs): Promise<boolean> {
if (!(await this.resetNodeManager())) {
return false
}
const kvs: [string, string][] = Object.entries(args).filter(([_k, v]) => v) as [string, string][]
const kvs: [string, string][] = Object.entries(args).filter(
([_k, v]) => v,
) as [string, string][]
await Promise.all([
...kvs.map(([k, v]) => this.updateConfig(k, v!)),