merge 0.4.0
This commit is contained in:
parent
08da9c63f0
commit
d75feb3ee1
@ -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()
|
||||
}()
|
||||
```
|
||||
```
|
13
package.json
13
package.json
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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包括:{licence,projectDir,yjsPath,dataChain,doipConfig,nodeCenter,nodeName,masterAddress,resetNodeCenterWS}
|
||||
@ -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!)),
|
||||
|
Loading…
Reference in New Issue
Block a user