initial commit
This commit is contained in:
commit
3ee7b5bfc7
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.idea
|
||||
node_modules
|
||||
dist
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 The BDWare Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
79
README.md
Normal file
79
README.md
Normal file
@ -0,0 +1,79 @@
|
||||
# BDContract SDK
|
||||
|
||||
BDContract SDK for Node.js and browsers.
|
||||
|
||||
## Install
|
||||
|
||||
`npm install @bdware/bdcontract-sdk`
|
||||
|
||||
```typescript
|
||||
import { Client } from '@bdware/bdcontract-sdk'
|
||||
import { sm2 } from 'sm-crypto'
|
||||
const client = new Client(
|
||||
url,
|
||||
(ev) => {
|
||||
console.log(JSON.stringify(ev))
|
||||
},
|
||||
(ev, ws) => {
|
||||
console.log(ev.data)
|
||||
},
|
||||
sm2.generateKeyPairHex(),
|
||||
)
|
||||
```
|
||||
|
||||
To use with plain HTML and JavaScript, include [dist/bdcontract-sdk.umd.js](dist/bdcontract-sdk.umd.js) (example from [test/index.html](test/index.html)):
|
||||
|
||||
```HTML
|
||||
<script type="text/javascript" src="./sm2.js"></script>
|
||||
<script type="text/javascript" src="./cryptico.iife.js"></script>
|
||||
<script type="text/javascript" src="../dist/bdcontract-sdk.iife.js"></script>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
// Approach 1:
|
||||
const wssocket = new WsSocket(url, wsHandler)
|
||||
|
||||
// Approach 2:
|
||||
function print(string) {
|
||||
document.write(string + '\n\n')
|
||||
}
|
||||
|
||||
const url = 'ws://021.node.internetapi.cn:21030/SCIDE/SCExecutor'
|
||||
|
||||
const client = new bdcontract.Client(
|
||||
url,
|
||||
(ev) => {
|
||||
console.log(JSON.stringify(ev))
|
||||
},
|
||||
(ev, ws) => {
|
||||
console.log(ev.data)
|
||||
},
|
||||
)
|
||||
setTimeout(async () => {
|
||||
const status = client.status()
|
||||
console.log(status)
|
||||
try {
|
||||
let data = await client.executeContract(
|
||||
'AnnotationExample0608',
|
||||
'main',
|
||||
'abacd',
|
||||
)
|
||||
print(JSON.stringify(data))
|
||||
} catch (data) {
|
||||
print(JSON.stringify(data))
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
// Wait for session receival
|
||||
const session = await client.sessionReceived()
|
||||
|
||||
// Login and wait (will wait if session not yet received)
|
||||
const success = await client.login()
|
||||
|
||||
async function anotherPlace() {
|
||||
// In another place, wait for login to complete
|
||||
const success = await client.Loggedin()
|
||||
}()
|
||||
```
|
238
lib/index.d.ts
vendored
Normal file
238
lib/index.d.ts
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
import { AESKey, RSAKey } from '@daotl/cryptico';
|
||||
import { AxiosRequestConfig } from 'axios';
|
||||
import { KeyPairHex } from 'sm-crypto';
|
||||
|
||||
declare function aesEncrypt(data: string, aesKey: AESKey): string;
|
||||
declare function rsaEncrypt(data: string, rsaKey: {
|
||||
n: string;
|
||||
e1: string;
|
||||
}): string;
|
||||
declare function loadRSAKey(rsaKey: string): RSAKey;
|
||||
declare function encryptReq(reqContent: {
|
||||
contractID: string;
|
||||
}, pubKey: RSAKey): {
|
||||
action: string | null;
|
||||
contractID: string;
|
||||
arg: string;
|
||||
requester: string;
|
||||
};
|
||||
|
||||
type ClientResponse<Data> = Omit<Response, 'data'> & {
|
||||
data?: Data;
|
||||
};
|
||||
type PingResponse = ClientResponse<'pong'>;
|
||||
interface SaveFileRequest {
|
||||
content: string;
|
||||
isAppend: boolean;
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
}
|
||||
interface ListProjectPermissionRequest {
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
}
|
||||
interface ListProjectPermissionResponseData {
|
||||
permissions: string[];
|
||||
ypk: string;
|
||||
}
|
||||
interface StartContractByYpkRequest {
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
script: string;
|
||||
}
|
||||
interface ListAllUsersResponseDataListItem {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
interface ListAllUsersResponseData {
|
||||
kv: ListAllUsersResponseDataListItem[];
|
||||
time: ListAllUsersResponseDataListItem[];
|
||||
}
|
||||
interface OnlineContractsItem {
|
||||
contractID: string;
|
||||
contractName: string;
|
||||
isMaster: boolean;
|
||||
type: string;
|
||||
yjsType: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
interface OnlineItem {
|
||||
cimanager: string;
|
||||
contractVersion: number;
|
||||
events: number;
|
||||
ipPort: string;
|
||||
masterAddress: string;
|
||||
nodeName: string;
|
||||
peerID: string;
|
||||
pubKey: string;
|
||||
contracts: OnlineContractsItem[];
|
||||
}
|
||||
interface ListNodesResponse {
|
||||
action: string;
|
||||
offline: string[];
|
||||
online: OnlineItem[];
|
||||
}
|
||||
interface DistributeContractResponse {
|
||||
action: string;
|
||||
progress: string;
|
||||
}
|
||||
interface ExecuteContractArgs extends RequestInit {
|
||||
method?: 'POST' | 'GET';
|
||||
withSignature?: boolean;
|
||||
withDynamicAnalysis?: boolean;
|
||||
}
|
||||
interface ExecuteContractResponse<Data> {
|
||||
status?: boolean;
|
||||
data?: Data;
|
||||
executeTime?: number;
|
||||
cid?: string;
|
||||
isPrivate?: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
interface ConfigNodeArgs {
|
||||
nodeName?: string;
|
||||
dataChain?: string;
|
||||
masterAddress?: string;
|
||||
nodeCenter?: string;
|
||||
LHSProxyAddress?: string;
|
||||
[K: string]: string | undefined;
|
||||
}
|
||||
interface LoadNodeConfigResponseData {
|
||||
doipConfig: string;
|
||||
[K: string]: string;
|
||||
}
|
||||
|
||||
declare class HttpClient {
|
||||
private baseUrl;
|
||||
private sm2Key;
|
||||
private fetch;
|
||||
constructor(baseUrl: string, sm2Key: KeyPairHex, config?: AxiosRequestConfig<any>);
|
||||
requestWithSignature<Data>(path: string, init?: Partial<RequestInit>, sm2Key?: KeyPairHex): Promise<ClientResponse<Data>>;
|
||||
retryRequestWithSignature<Data>(retryTimes: number, path: string, init?: Partial<RequestInit>, sm2Key?: KeyPairHex): Promise<ClientResponse<Data>>;
|
||||
sign(data: string, privateKey?: string): string;
|
||||
ping(): Promise<PingResponse>;
|
||||
startContract(code: string): Promise<ClientResponse<string>>;
|
||||
startContractByYPK(_request: StartContractByYpkRequest): Promise<ClientResponse<string>>;
|
||||
executeContract(contractID: string, operation: string, arg: string, { method, withDynamicAnalysis, withSignature, }?: ExecuteContractArgs): Promise<ClientResponse<ExecuteContractResponse<string>>>;
|
||||
killContractProcess(contractID: string, requestID?: string): Promise<ClientResponse<string>>;
|
||||
killAllContract(): Promise<ClientResponse<string>>;
|
||||
applyNodeRole(role: string): Promise<ClientResponse<{
|
||||
action: string;
|
||||
data: string;
|
||||
role?: string;
|
||||
}>>;
|
||||
authNodeRole(isAccept: boolean, authorizedPubKey: string, managerPair?: KeyPairHex): Promise<ClientResponse<{
|
||||
action: string;
|
||||
data: string;
|
||||
}>>;
|
||||
distributeContract(nodeIDs: string, projectName: string, isPrivate: boolean): void;
|
||||
saveFile(_request: SaveFileRequest): Promise<ClientResponse<string>>;
|
||||
listProjectPermission(_request: ListProjectPermissionRequest): Promise<ClientResponse<ListProjectPermissionResponseData>>;
|
||||
startContractMultiPoint(peersID: string, type: number, selectUnitNum: number, projectName: string, isPrivate: boolean, sponsorPeerID: string): Promise<ClientResponse<string>>;
|
||||
loadNodeConfig(): Promise<ClientResponse<LoadNodeConfigResponseData>>;
|
||||
updateConfig(key: string, val: string): Promise<ClientResponse<boolean>>;
|
||||
resetNodeManager(): Promise<boolean>;
|
||||
lockEdit(): Promise<ClientResponse<string>>;
|
||||
unlockEdit(): Promise<ClientResponse<string>>;
|
||||
addNode(nodePubKey: string): Promise<ClientResponse<string>>;
|
||||
applyRole(role: string): Promise<ClientResponse<string>>;
|
||||
authNodeManager(isAccept: boolean, authorizedPubKey: string): Promise<ClientResponse<string>>;
|
||||
listAllUsers(): Promise<ClientResponse<ListAllUsersResponseData>>;
|
||||
listNodes(): Promise<ListNodesResponse>;
|
||||
createTrustUnit(data: {
|
||||
nodeName: string;
|
||||
pubkey: string;
|
||||
}[], Msg: string): Promise<{
|
||||
action: string;
|
||||
status: string;
|
||||
}>;
|
||||
listTrustUnits(): Promise<ClientResponse<{
|
||||
key: string;
|
||||
value: string;
|
||||
}[]>>;
|
||||
listContractProcess(): Promise<ClientResponse<string>>;
|
||||
downloadContract(projectName: string, isPrivate: boolean, timestamp: number): Promise<ClientResponse<string>>;
|
||||
configNode(args: ConfigNodeArgs): Promise<boolean>;
|
||||
}
|
||||
|
||||
interface WsEvent {
|
||||
data: string;
|
||||
}
|
||||
type OnOpenHandler = (this: WebSocket, ev: Event) => void;
|
||||
type WsHandler = (ev: WsEvent, ws?: WebSocket) => void;
|
||||
interface SegmentData {
|
||||
action: 'sendSeg';
|
||||
cid: string;
|
||||
data: string;
|
||||
}
|
||||
declare class WsSocket {
|
||||
private handlerList;
|
||||
private toSend;
|
||||
private isSending;
|
||||
private sendList;
|
||||
private toReceive;
|
||||
private wssocket;
|
||||
constructor(wsurl: string, onopen: OnOpenHandler, handler?: WsHandler);
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'];
|
||||
sendNextSegment(): void;
|
||||
receiveSeg(obj: SegmentData): void;
|
||||
monitor(): void;
|
||||
send(data: string): void;
|
||||
addHandler(handler: WsHandler): void;
|
||||
}
|
||||
|
||||
interface ResponseData {
|
||||
action: string;
|
||||
responseID?: string;
|
||||
status: true | false | string;
|
||||
result?: unknown;
|
||||
data: string;
|
||||
[K: string]: unknown;
|
||||
}
|
||||
declare class WsClient {
|
||||
private readonly sm2Key;
|
||||
private readonly wssocket;
|
||||
private readonly promiseCallbackPairs;
|
||||
private readonly sessionPromise;
|
||||
private sessionResolve;
|
||||
private readonly loginPromise;
|
||||
private loginResolve;
|
||||
constructor(url: string, onopen: OnOpenHandler, handler: WsHandler, sm2Key?: KeyPairHex);
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'];
|
||||
sessionReceived(): Promise<string>;
|
||||
login(): Promise<boolean>;
|
||||
loggedIn(): Promise<boolean>;
|
||||
matchCID(contractID: string): Promise<ResponseData>;
|
||||
getMetabyCID(contractID: string): Promise<ResponseData>;
|
||||
getMetabyReadme(keyword: string, page?: string, pageSize?: string): Promise<ResponseData>;
|
||||
getMetabyPubkey(pubkey: string): Promise<ResponseData>;
|
||||
segmentWord(words: string): Promise<ResponseData>;
|
||||
getMetabyOwner(owner: string, page?: string, pageSize?: string): Promise<ResponseData>;
|
||||
getDependentContract(contractName: string): Promise<ResponseData>;
|
||||
queryContractLogByDate(start: number): Promise<ResponseData>;
|
||||
queryDataByHash(hash: string): Promise<ResponseData>;
|
||||
executeContract(contractID: string, method: string, arg: unknown): Promise<ResponseData>;
|
||||
getSessionID(): Promise<ResponseData>;
|
||||
listTheContractProcess(contractID: string): Promise<ResponseData>;
|
||||
getMask(contractID: string): Promise<ResponseData>;
|
||||
setMask(contractID: string, operation: string, arg: string): Promise<ResponseData>;
|
||||
getMock(contractID: string): Promise<ResponseData>;
|
||||
setMock(contractID: string, operation: string, arg: string): Promise<ResponseData>;
|
||||
queryHashByOffset(offset: number, count: number): Promise<ResponseData>;
|
||||
loadNodeConfig(): Promise<ResponseData>;
|
||||
queryUserStat(): Promise<ResponseData>;
|
||||
listNodes(): Promise<ResponseData>;
|
||||
killContractProcess(id: string): Promise<ResponseData>;
|
||||
distributeYPK(projectName: string, nodeIDs: string): Promise<ResponseData>;
|
||||
listYPKs(): Promise<ResponseData>;
|
||||
deleteFile(file: string): Promise<ResponseData>;
|
||||
startContractByYPK(project: string): Promise<ResponseData>;
|
||||
initBDServer(host: string, username: string, password: string, name: string, clusterHost: string): Promise<ResponseData>;
|
||||
initBDCluster(host: string, username: string, password: string, name: string, sm2Key: string, agents: []): Promise<ResponseData>;
|
||||
listCompiledFiles(): Promise<ResponseData>;
|
||||
getManagerPubkey(): Promise<ResponseData>;
|
||||
getClusterName(): Promise<ResponseData>;
|
||||
setClusterName(name: string): Promise<ResponseData>;
|
||||
}
|
||||
|
||||
export { ClientResponse, ConfigNodeArgs, DistributeContractResponse, ExecuteContractArgs, ExecuteContractResponse, HttpClient, ListAllUsersResponseData, ListAllUsersResponseDataListItem, ListNodesResponse, ListProjectPermissionRequest, ListProjectPermissionResponseData, LoadNodeConfigResponseData, OnOpenHandler, OnlineContractsItem, OnlineItem, PingResponse, SaveFileRequest, StartContractByYpkRequest, WsClient, WsEvent, WsHandler, WsSocket, aesEncrypt, encryptReq, loadRSAKey, rsaEncrypt };
|
2
lib/index.js
Normal file
2
lib/index.js
Normal file
File diff suppressed because one or more lines are too long
1
lib/index.js.map
Normal file
1
lib/index.js.map
Normal file
File diff suppressed because one or more lines are too long
2
lib/index.mjs
Normal file
2
lib/index.mjs
Normal file
File diff suppressed because one or more lines are too long
1
lib/index.mjs.map
Normal file
1
lib/index.mjs.map
Normal file
File diff suppressed because one or more lines are too long
51
package.json
Normal file
51
package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "@bdware/bdcontract-sdk",
|
||||
"version": "0.3.0-alpha.14",
|
||||
"description": "BDContract SDK for Node.js and browsers",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"BDWare",
|
||||
"BDContract",
|
||||
"SDK",
|
||||
"WebSocket",
|
||||
"TypeScript",
|
||||
"Node.js",
|
||||
"node",
|
||||
"nodejs",
|
||||
"browser"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.mjs",
|
||||
"iife": "dist/bdcontract-sdk.iife.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "shx rm -rf lib dist && rollup -c rollup.config.js",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"pub": "npm run lint && npm publish --access public"
|
||||
},
|
||||
"prettier": "@daotl/prettier-config",
|
||||
"dependencies": {
|
||||
"@daotl/cryptico": "^2.0.3",
|
||||
"@lifeomic/axios-fetch": "^3.0.0",
|
||||
"axios": "^0.27.2",
|
||||
"sm-crypto": "^0.3.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@daotl/eslint-config": "^0.3.31",
|
||||
"@types/node": "^18.7.15",
|
||||
"@types/sm-crypto": "^0.3.0",
|
||||
"eslint": "^8.23.0",
|
||||
"prettier": "^2.7.1",
|
||||
"rollup": "^2.79.0",
|
||||
"rollup-plugin-dts": "^4.2.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-typescript2": "^0.33.0",
|
||||
"shx": "^0.3.4",
|
||||
"sucrase": "^3.25.0",
|
||||
"typescript": "^4.8.2"
|
||||
}
|
||||
}
|
2
rollup.config.js
Normal file
2
rollup.config.js
Normal file
@ -0,0 +1,2 @@
|
||||
require('sucrase/register')
|
||||
module.exports = require('./rollup.config.ts')
|
41
rollup.config.ts
Normal file
41
rollup.config.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import type { RollupOptions } from 'rollup'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
|
||||
const pkg = require('./package.json')
|
||||
|
||||
const name = 'bdcontract'
|
||||
|
||||
export default [
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: [
|
||||
{
|
||||
file: `${pkg.main}`,
|
||||
format: 'umd',
|
||||
name,
|
||||
sourcemap: true,
|
||||
},
|
||||
{ file: `${pkg.module}`, format: 'es', sourcemap: true },
|
||||
{
|
||||
file: `${pkg.iife}`,
|
||||
format: 'iife',
|
||||
name,
|
||||
sourcemap: true,
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.build.json',
|
||||
useTsconfigDeclarationDir: true,
|
||||
}),
|
||||
terser(),
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'types/index.d.ts',
|
||||
output: [{ file: 'lib/index.d.ts' }],
|
||||
plugins: [dts()],
|
||||
},
|
||||
] as RollupOptions
|
77
src/crypto.ts
Normal file
77
src/crypto.ts
Normal file
@ -0,0 +1,77 @@
|
||||
// export function aesDecrypt(data: base64) {
|
||||
// const dataAscii = cryptico.b64to256(data)
|
||||
// const encryptedBlocks = cryptico.string2bytes(dataAscii)
|
||||
// const exkey = global.aesKey.slice(0)
|
||||
// aes.ExpandKey(exkey)
|
||||
// aes.Decrypt(encryptedBlocks, exkey)
|
||||
// return cryptico.bytes2string(encryptedBlocks)
|
||||
// }
|
||||
|
||||
import type { AESKey } from '@daotl/cryptico'
|
||||
import { aes, cryptico, RSAKey } from '@daotl/cryptico'
|
||||
|
||||
export function aesEncrypt(data: string, aesKey: AESKey): string {
|
||||
const exkey = aesKey.slice(0)
|
||||
aes.ExpandKey(exkey)
|
||||
let blocks = cryptico.string2bytes(data)
|
||||
blocks = cryptico.pad16(blocks)
|
||||
aes.Encrypt(blocks, exkey)
|
||||
let ciphertext = cryptico.bytes2string(blocks)
|
||||
ciphertext = cryptico.b256to64(ciphertext)
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
export function rsaEncrypt(
|
||||
data: string,
|
||||
rsaKey: { n: string; e1: string },
|
||||
): string {
|
||||
const rsa = new RSAKey()
|
||||
rsa.setPublic(rsaKey.n, rsaKey.e1)
|
||||
return rsa.encrypt(data)
|
||||
}
|
||||
|
||||
export function loadRSAKey(rsaKey: string): RSAKey {
|
||||
const str = cryptico.b64to256(rsaKey)
|
||||
const strs = str.split(',')
|
||||
const key = new RSAKey()
|
||||
key.setPrivate(strs[0], strs[0], strs[0])
|
||||
return key
|
||||
}
|
||||
|
||||
// function testRSA() {
|
||||
// pubKey = loadRSAKey(global.privKey)
|
||||
// reqContent = {}
|
||||
// reqContent.action = 'main'
|
||||
// reqContent.arg = '[{"score":20},{"score":20}]'
|
||||
// reqContent.contractID = 'abc'
|
||||
// eReq = encryptReq(reqContent, pubKey)
|
||||
// url =
|
||||
// 'http://localhost:8080/SCIDE/SCManager?action=executeContractEncrypted&contractRequest=' +
|
||||
// encodeURIComponent(JSON.stringify(eReq))
|
||||
// }
|
||||
|
||||
export function encryptReq(
|
||||
reqContent: { contractID: string },
|
||||
pubKey: RSAKey,
|
||||
): {
|
||||
action: string | null
|
||||
contractID: string
|
||||
arg: string
|
||||
requester: string
|
||||
} {
|
||||
const aes = {
|
||||
key: cryptico.generateAESKey(),
|
||||
}
|
||||
const aesObj = JSON.stringify(aes)
|
||||
const { contractID } = reqContent
|
||||
const reqContentNoId = { ...reqContent, contractID: undefined }
|
||||
const encrypedReq = {
|
||||
action: pubKey.decrypt(aesObj),
|
||||
contractID,
|
||||
arg: aesEncrypt(JSON.stringify(reqContentNoId), aes.key),
|
||||
requester: cryptico.b256to64(
|
||||
`${pubKey.n.toString(16)},${pubKey.e.toString(16)},0`,
|
||||
),
|
||||
}
|
||||
return encrypedReq
|
||||
}
|
582
src/httpClient.ts
Normal file
582
src/httpClient.ts
Normal file
@ -0,0 +1,582 @@
|
||||
import { buildAxiosFetch } from '@lifeomic/axios-fetch'
|
||||
import axios, { type AxiosRequestConfig } from 'axios'
|
||||
import type { KeyPairHex } from 'sm-crypto'
|
||||
import { sm2 } from 'sm-crypto'
|
||||
|
||||
import type {
|
||||
ClientResponse,
|
||||
ConfigNodeArgs,
|
||||
ExecuteContractArgs,
|
||||
ListAllUsersResponseData,
|
||||
ListNodesResponse,
|
||||
ListProjectPermissionRequest,
|
||||
ListProjectPermissionResponseData,
|
||||
LoadNodeConfigResponseData,
|
||||
ExecuteContractResponse,
|
||||
PingResponse,
|
||||
SaveFileRequest,
|
||||
StartContractByYpkRequest,
|
||||
} from './types'
|
||||
|
||||
const genUrlParamsFromObject = (obj: Record<string, unknown>): string => {
|
||||
return Object.entries(obj)
|
||||
.map(([key, value]) => `${key}=${String(value)}`)
|
||||
.join('&')
|
||||
}
|
||||
|
||||
export * from './types'
|
||||
|
||||
export class HttpClient {
|
||||
private fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>
|
||||
|
||||
constructor(
|
||||
private baseUrl: string,
|
||||
private sm2Key: KeyPairHex,
|
||||
config = {} as AxiosRequestConfig,
|
||||
) {
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: 'https://some-domain.com/api/',
|
||||
timeout: 10000,
|
||||
// headers: {'X-Custom-Header': 'foobar'}
|
||||
...config,
|
||||
})
|
||||
|
||||
this.fetch = buildAxiosFetch(
|
||||
axiosInstance /* , function (config) {
|
||||
config.timeout = 1000;
|
||||
return config;
|
||||
} */,
|
||||
)
|
||||
}
|
||||
|
||||
async requestWithSignature<Data>(
|
||||
path: string,
|
||||
init?: Partial<RequestInit>,
|
||||
sm2Key?: KeyPairHex,
|
||||
): Promise<ClientResponse<Data>> {
|
||||
return new Promise<ClientResponse<Data>>((resolve, reject) => {
|
||||
const rawUrl = this.baseUrl + path
|
||||
const url = `${rawUrl}${path.includes('?') ? '&' : '?'}pubKey=${
|
||||
sm2Key?.publicKey ?? this.sm2Key.publicKey
|
||||
}`
|
||||
|
||||
// console.log('privateKey:', this.sm2Key.privateKey)
|
||||
|
||||
// console.log('publicKey:', this.sm2Key.publicKey)
|
||||
|
||||
// console.log('to sign:', url.substring(url.indexOf('?') + 1))
|
||||
|
||||
const sign = this.sign(
|
||||
url.substring(url.indexOf('?') + 1),
|
||||
sm2Key?.privateKey,
|
||||
)
|
||||
|
||||
// console.log(
|
||||
// 'url:',
|
||||
// init?.method?.toLowerCase() === 'post'
|
||||
// ? rawUrl
|
||||
// : `${encodeURI(url)}&sign=${sign}`,
|
||||
// )
|
||||
|
||||
this.fetch(
|
||||
init?.method?.toLowerCase() === 'post'
|
||||
? rawUrl
|
||||
: `${encodeURI(url)}&sign=${sign}`,
|
||||
{
|
||||
...init,
|
||||
...(init?.method === 'POST'
|
||||
? {
|
||||
body: {
|
||||
...(init?.body as unknown as Record<string, string>),
|
||||
sign,
|
||||
} as unknown as Request['body'],
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
)
|
||||
.then(async (res) => {
|
||||
// console.log(res.url,'请求成功')
|
||||
const clientRes = res as unknown as ClientResponse<Data>
|
||||
clientRes.data = (await res.text()) as Data
|
||||
// Workaround for the issue causing the 2nd consecutive request to fail:
|
||||
// https://github.com/nodejs/undici/issues/1415
|
||||
setTimeout(() => {
|
||||
resolve(clientRes)
|
||||
}, 1)
|
||||
})
|
||||
.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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
der: true,
|
||||
})
|
||||
}
|
||||
|
||||
// ping
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id15
|
||||
ping(): Promise<PingResponse> {
|
||||
return 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)}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 启动合约
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id13
|
||||
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,
|
||||
},
|
||||
),
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 调用合约
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id69
|
||||
executeContract(
|
||||
contractID: string,
|
||||
operation: string,
|
||||
arg: string,
|
||||
{
|
||||
method = 'POST',
|
||||
withDynamicAnalysis = false,
|
||||
withSignature = false,
|
||||
} = {} as ExecuteContractArgs,
|
||||
): Promise<ClientResponse<ExecuteContractResponse<string>>> {
|
||||
let request = {}
|
||||
if (withDynamicAnalysis === undefined) {
|
||||
request = {
|
||||
action: 'executeContract',
|
||||
contractID,
|
||||
operation,
|
||||
arg,
|
||||
}
|
||||
} else {
|
||||
request = {
|
||||
action: 'executeContract',
|
||||
contractID,
|
||||
operation,
|
||||
withDynamicAnalysis,
|
||||
arg,
|
||||
}
|
||||
}
|
||||
if (withSignature) {
|
||||
request = {
|
||||
...request,
|
||||
pubkey: this.sm2Key.publicKey,
|
||||
signature: this.sign(
|
||||
`${contractID}|${operation}|${arg ?? ''}|${this.sm2Key.publicKey}`,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
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) : {}),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// 停止合约
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html#id122
|
||||
killContractProcess(
|
||||
contractID: string,
|
||||
requestID?: string,
|
||||
): Promise<ClientResponse<string>> {
|
||||
const _request: Record<string, string> = {
|
||||
action: 'killContractProcess',
|
||||
id: contractID,
|
||||
}
|
||||
requestID && (_request.requestID = requestID!)
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject(_request)}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 停止所有合约
|
||||
// 地址 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')
|
||||
}
|
||||
|
||||
// 申请角色
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html
|
||||
applyNodeRole(
|
||||
role: string,
|
||||
): Promise<ClientResponse<{ action: string; data: string; role?: string }>> {
|
||||
const _request = {
|
||||
action: 'applyNodeRole',
|
||||
role,
|
||||
}
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject(_request)}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 授权角色
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html
|
||||
authNodeRole(
|
||||
isAccept: boolean,
|
||||
authorizedPubKey: string,
|
||||
managerPair?: KeyPairHex,
|
||||
): Promise<ClientResponse<{ action: string; data: string }>> {
|
||||
const _request = {
|
||||
action: 'authNodeRole',
|
||||
isAccept,
|
||||
authorizedPubKey,
|
||||
}
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject(_request)}`,
|
||||
undefined,
|
||||
managerPair,
|
||||
)
|
||||
}
|
||||
|
||||
// https://public.internetapi.cn/docs/bdcontract/doc/ContractAPI.html
|
||||
// 用sse获取 问题未解决!!!
|
||||
distributeContract(
|
||||
nodeIDs: string,
|
||||
projectName: string,
|
||||
isPrivate: boolean,
|
||||
): void {
|
||||
const signature = sm2.doSignature(
|
||||
`DistributeContract|${projectName}|${this.sm2Key.publicKey}`,
|
||||
this.sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
)
|
||||
|
||||
const _request = {
|
||||
action: 'distributeContract',
|
||||
nodeIDs,
|
||||
projectName,
|
||||
isPrivate,
|
||||
signature,
|
||||
}
|
||||
|
||||
const path = `/SCManager?${genUrlParamsFromObject(_request)}`
|
||||
const url = `${this.baseUrl + path}${
|
||||
path.includes('?') ? '&' : '?'
|
||||
}pubKey=${this.sm2Key.publicKey}`
|
||||
const sig = sm2.doSignature(
|
||||
url.substring(url.indexOf('?') + 1),
|
||||
this.sm2Key.privateKey,
|
||||
{
|
||||
hash: true,
|
||||
der: true,
|
||||
},
|
||||
)
|
||||
const source = new EventSource(
|
||||
`${this.baseUrl}${path}&pubKey=${this.sm2Key.publicKey}&sign=${sig}`,
|
||||
)
|
||||
source.addEventListener(
|
||||
'message',
|
||||
function (_event) {
|
||||
// const data = event.data as DistributeContractResponse[]
|
||||
// console.log(data, 'dd')
|
||||
// handle message
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
saveFile(_request: SaveFileRequest): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'saveFile',
|
||||
..._request,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
listProjectPermission(
|
||||
_request: ListProjectPermissionRequest,
|
||||
): Promise<ClientResponse<ListProjectPermissionResponseData>> {
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'listProjectPermission',
|
||||
..._request,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
startContractMultiPoint(
|
||||
peersID: string,
|
||||
type: number,
|
||||
selectUnitNum: number,
|
||||
projectName: string,
|
||||
isPrivate: boolean,
|
||||
sponsorPeerID: string,
|
||||
): Promise<ClientResponse<string>> {
|
||||
const _request = {
|
||||
// peerID是节点的公钥,以逗号间隔开
|
||||
peersID,
|
||||
type,
|
||||
selectUnitNum,
|
||||
projectName,
|
||||
isPrivate,
|
||||
sponsorPeerID,
|
||||
}
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'startContractMultiPoint',
|
||||
..._request,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 获取节点配置信息
|
||||
async loadNodeConfig(): Promise<ClientResponse<LoadNodeConfigResponseData>> {
|
||||
const res = await this.requestWithSignature<string>(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'loadNodeConfig',
|
||||
})}`,
|
||||
)
|
||||
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}
|
||||
async updateConfig(
|
||||
key: string,
|
||||
val: string,
|
||||
): Promise<ClientResponse<boolean>> {
|
||||
return 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',
|
||||
})}`,
|
||||
)
|
||||
if (!res.data) {
|
||||
return false
|
||||
}
|
||||
const parsed = JSON.parse(res.data)
|
||||
return parsed.data === 'success'
|
||||
}
|
||||
|
||||
// 锁定某个用户的的私有目录编辑功能
|
||||
lockEdit(): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'lockEdit',
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 解锁某个用户的的私有目录编辑功能
|
||||
unlockEdit(): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'unlockEdit',
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
addNode(nodePubKey: string): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'addNode',
|
||||
nodePubKey,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 申请角色
|
||||
applyRole(role: string): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'applyRole',
|
||||
role,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
authNodeManager(
|
||||
isAccept: boolean,
|
||||
authorizedPubKey: string,
|
||||
): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'authNodeManager',
|
||||
isAccept,
|
||||
authorizedPubKey,
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
listAllUsers(): Promise<ClientResponse<ListAllUsersResponseData>> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'listAllUsers',
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 查看节点列表
|
||||
listNodes(): Promise<ListNodesResponse> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'listNodes',
|
||||
})}`,
|
||||
) as unknown as Promise<ListNodesResponse>
|
||||
}
|
||||
|
||||
// 建立可信执行集群
|
||||
async createTrustUnit(
|
||||
data: { nodeName: string; pubkey: string }[],
|
||||
Msg: string,
|
||||
): Promise<{ action: string; status: string }> {
|
||||
const toSign = `action=createTrustUnit&data=${JSON.stringify(
|
||||
data,
|
||||
)}&msg=${Msg}&pubKey=04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27`
|
||||
const sig = sm2.doSignature(toSign, this.sm2Key.privateKey, {
|
||||
hash: true,
|
||||
der: true,
|
||||
})
|
||||
|
||||
const body = {
|
||||
action: 'createTrustUnit',
|
||||
data,
|
||||
msg: Msg,
|
||||
pubKey:
|
||||
'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 }
|
||||
}
|
||||
|
||||
// 查看可信执行集群列表
|
||||
listTrustUnits(): Promise<ClientResponse<{ key: string; value: string }[]>> {
|
||||
return this.requestWithSignature(
|
||||
`?${genUrlParamsFromObject({
|
||||
action: 'listTrustUnits',
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// listContractProcess 查询合约实例列表
|
||||
listContractProcess(): Promise<ClientResponse<string>> {
|
||||
return this.requestWithSignature(
|
||||
`/SCManager?${genUrlParamsFromObject({
|
||||
action: 'listContractProcess',
|
||||
})}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 下载合约
|
||||
downloadContract(
|
||||
projectName: string,
|
||||
isPrivate: boolean,
|
||||
timestamp: number
|
||||
): Promise<ClientResponse<string>> {
|
||||
const _request = {
|
||||
action: 'downloadContract',
|
||||
projectName,
|
||||
isPrivate,
|
||||
timestamp,
|
||||
}
|
||||
return this.requestWithSignature(
|
||||
`/CMManager?${genUrlParamsFromObject(_request)}`)
|
||||
}
|
||||
|
||||
// 配置合约引擎节点,若节点没有设置过node manager,将当前key设置为node manager
|
||||
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][]
|
||||
|
||||
await Promise.all([
|
||||
...kvs.map(([k, v]) => this.updateConfig(k, v!)),
|
||||
this.applyNodeRole('ContractProvider'),
|
||||
this.applyNodeRole('ContractUser'),
|
||||
this.applyNodeRole('ContractInstanceManager'),
|
||||
this.authNodeRole(true, this.sm2Key.publicKey),
|
||||
])
|
||||
|
||||
const config = (await this.loadNodeConfig()).data
|
||||
if (!config) {
|
||||
return false
|
||||
}
|
||||
|
||||
return kvs.every(([k, v]) => config[remapNodeConfigKey(k)] === v)
|
||||
}
|
||||
}
|
||||
|
||||
function remapNodeConfigKey(k: string) {
|
||||
switch (k) {
|
||||
case 'dataChain':
|
||||
return 'bdledger'
|
||||
default:
|
||||
return k
|
||||
}
|
||||
}
|
4
src/index.ts
Normal file
4
src/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './crypto'
|
||||
export * from './httpClient'
|
||||
export * from './wsClient'
|
||||
export * from './wssocket'
|
101
src/types.ts
Normal file
101
src/types.ts
Normal file
@ -0,0 +1,101 @@
|
||||
export type ClientResponse<Data> = Omit<Response, 'data'> & {
|
||||
data?: Data
|
||||
}
|
||||
|
||||
export type PingResponse = ClientResponse<'pong'>
|
||||
|
||||
export interface SaveFileRequest {
|
||||
content: string
|
||||
isAppend: boolean
|
||||
isPrivate: boolean
|
||||
path: string
|
||||
}
|
||||
|
||||
export interface ListProjectPermissionRequest {
|
||||
isPrivate: boolean
|
||||
path: string
|
||||
}
|
||||
|
||||
export interface ListProjectPermissionResponseData {
|
||||
permissions: string[]
|
||||
ypk: string
|
||||
}
|
||||
|
||||
export interface StartContractByYpkRequest {
|
||||
isPrivate: boolean
|
||||
path: string
|
||||
script: string
|
||||
// signature: string
|
||||
}
|
||||
|
||||
export interface ListAllUsersResponseDataListItem {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
export interface ListAllUsersResponseData {
|
||||
kv: ListAllUsersResponseDataListItem[]
|
||||
time: ListAllUsersResponseDataListItem[]
|
||||
}
|
||||
export interface OnlineContractsItem {
|
||||
contractID: string
|
||||
contractName: string
|
||||
isMaster: boolean
|
||||
type: string
|
||||
yjsType: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
export interface OnlineItem {
|
||||
cimanager: string
|
||||
contractVersion: number
|
||||
events: number
|
||||
ipPort: string
|
||||
masterAddress: string
|
||||
nodeName: string
|
||||
peerID: string
|
||||
pubKey: string
|
||||
contracts: OnlineContractsItem[]
|
||||
}
|
||||
|
||||
export interface ListNodesResponse {
|
||||
action: string
|
||||
offline: string[]
|
||||
online: OnlineItem[]
|
||||
}
|
||||
|
||||
export interface DistributeContractResponse {
|
||||
action: string
|
||||
progress: string
|
||||
}
|
||||
|
||||
export interface ExecuteContractArgs extends RequestInit {
|
||||
method?: 'POST' | 'GET'
|
||||
// 是否使用签名
|
||||
withSignature?: boolean
|
||||
withDynamicAnalysis?: boolean
|
||||
}
|
||||
|
||||
export interface ExecuteContractResponse<Data> {
|
||||
// ok: boolean
|
||||
status?: boolean
|
||||
// statusText: string
|
||||
data?: Data
|
||||
executeTime?: number
|
||||
cid?: string
|
||||
isPrivate?: boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface ConfigNodeArgs {
|
||||
nodeName?: string
|
||||
dataChain?: string
|
||||
masterAddress?: string
|
||||
nodeCenter?: string
|
||||
// 配置中心节点时使用
|
||||
LHSProxyAddress?: string
|
||||
[K: string]: string | undefined
|
||||
}
|
||||
|
||||
export interface LoadNodeConfigResponseData {
|
||||
doipConfig: string
|
||||
[K: string]: string
|
||||
}
|
741
src/wsClient.ts
Normal file
741
src/wsClient.ts
Normal file
@ -0,0 +1,741 @@
|
||||
/* eslint-disable no-cond-assign */
|
||||
|
||||
import type { KeyPairHex } from 'sm-crypto'
|
||||
import { sm2 } from 'sm-crypto'
|
||||
|
||||
import type { OnOpenHandler, WsHandler } from './wssocket'
|
||||
import { WsSocket } from './wssocket'
|
||||
|
||||
interface ResponseData {
|
||||
action: string
|
||||
responseID?: string
|
||||
status: true | false | string // 'Success' | 'Exception' | 'Error' | 'failed: no session'
|
||||
result?: unknown
|
||||
data: string
|
||||
[K: string]: unknown
|
||||
}
|
||||
|
||||
// interface ListResponseData {
|
||||
// action: string
|
||||
// data: string
|
||||
// status: true | false
|
||||
// }
|
||||
|
||||
interface PromiseCallbackPair {
|
||||
resolve: (value: ResponseData | PromiseLike<ResponseData>) => void
|
||||
reject: (reason?: unknown) => void
|
||||
}
|
||||
|
||||
export class WsClient {
|
||||
private readonly sm2Key: KeyPairHex
|
||||
private readonly wssocket: WsSocket
|
||||
private readonly promiseCallbackPairs: Record<string, PromiseCallbackPair> =
|
||||
{}
|
||||
|
||||
private readonly sessionPromise: Promise<string>
|
||||
private sessionResolve!: (value: string | PromiseLike<string>) => void
|
||||
private readonly loginPromise: Promise<boolean>
|
||||
private loginResolve!: (value: boolean | PromiseLike<boolean>) => void
|
||||
|
||||
constructor(
|
||||
url: string,
|
||||
onopen: OnOpenHandler,
|
||||
handler: WsHandler,
|
||||
sm2Key: KeyPairHex = sm2.generateKeyPairHex(),
|
||||
) {
|
||||
this.sm2Key = sm2Key
|
||||
this.sessionPromise = new Promise((resolve, _reject) => {
|
||||
this.sessionResolve = resolve
|
||||
})
|
||||
this.loginPromise = new Promise((resolve, _reject) => {
|
||||
this.loginResolve = resolve
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const that = this
|
||||
this.wssocket = new WsSocket(url, onopen, function (
|
||||
this: WebSocket,
|
||||
event,
|
||||
_,
|
||||
) {
|
||||
const data = JSON.parse(event.data) as ResponseData
|
||||
|
||||
switch (data.action) {
|
||||
case 'onSessionID':
|
||||
that.sessionResolve(data.session as string)
|
||||
break
|
||||
case 'onLogin':
|
||||
{
|
||||
const failed =
|
||||
typeof data.status === 'string' &&
|
||||
data.status.toLowerCase().includes('failed')
|
||||
that.loginResolve(!failed)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
const reqId = data.responseID
|
||||
let pc: PromiseCallbackPair | undefined
|
||||
if (reqId && (pc = that.promiseCallbackPairs[reqId])) {
|
||||
if (data) {
|
||||
pc.resolve(data)
|
||||
} else {
|
||||
pc.reject(data)
|
||||
}
|
||||
}
|
||||
handler(event, this)
|
||||
})
|
||||
}
|
||||
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'] {
|
||||
return this.wssocket.status()
|
||||
}
|
||||
|
||||
sessionReceived(): Promise<string> {
|
||||
return this.sessionPromise
|
||||
}
|
||||
|
||||
async login(): Promise<boolean> {
|
||||
const session = await this.sessionPromise
|
||||
const request = {
|
||||
action: 'login',
|
||||
pubKey: this.sm2Key.publicKey,
|
||||
signature: sm2.doSignature(session, this.sm2Key.privateKey, {
|
||||
hash: true,
|
||||
der: true,
|
||||
}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return this.loginPromise
|
||||
}
|
||||
|
||||
loggedIn(): Promise<boolean> {
|
||||
return this.loginPromise
|
||||
}
|
||||
|
||||
matchCID(contractID: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'matchCID',
|
||||
contractID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMetabyCID(contractID: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMetabyCID',
|
||||
contractID,
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMetabyReadme(
|
||||
keyword: string,
|
||||
page?: string,
|
||||
pageSize?: string,
|
||||
): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMetabyReadme',
|
||||
page,
|
||||
pageSize,
|
||||
keyword,
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMetabyPubkey(pubkey: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMetabyPubkey',
|
||||
pubkey,
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
segmentWord(words: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
words,
|
||||
action: 'segmentWord',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMetabyOwner(
|
||||
owner: string,
|
||||
page?: string,
|
||||
pageSize?: string,
|
||||
): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMetabyOwner',
|
||||
owner,
|
||||
page,
|
||||
pageSize,
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getDependentContract(contractName: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getDependentContract',
|
||||
requestID,
|
||||
contractName,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
queryContractLogByDate(start: number): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'queryContractLogByDate',
|
||||
requestID,
|
||||
start,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
queryDataByHash(hash: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'queryDataByHash',
|
||||
requestID,
|
||||
hash,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
executeContract(
|
||||
contractID: string,
|
||||
method: string,
|
||||
arg: unknown,
|
||||
): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const argStr = (typeof arg) == 'object' ? JSON.stringify(arg):arg+"";
|
||||
const request = {
|
||||
action: 'executeContract',
|
||||
requestID,
|
||||
contractID,
|
||||
operation: method,
|
||||
arg: arg,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${method}|${argStr}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getSessionID(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getSessionID',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
listTheContractProcess(contractID: string): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'listTheContractProcess',
|
||||
requestID,
|
||||
contractID,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMask(
|
||||
contractID: string,
|
||||
// operation: string,
|
||||
): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMask',
|
||||
requestID,
|
||||
contractID,
|
||||
// operation,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
setMask(
|
||||
contractID: string,
|
||||
operation: string,
|
||||
arg: string,
|
||||
): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'setMask',
|
||||
requestID,
|
||||
contractID,
|
||||
operation,
|
||||
arg,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getMock(
|
||||
contractID: string,
|
||||
// operation: string,
|
||||
): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getMock',
|
||||
requestID,
|
||||
contractID,
|
||||
// operation,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
setMock(
|
||||
contractID: string,
|
||||
operation: string,
|
||||
arg: string,
|
||||
): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'setMock',
|
||||
requestID,
|
||||
contractID,
|
||||
operation,
|
||||
arg,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(
|
||||
`${contractID}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
queryHashByOffset(offset: number, count: number): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'queryHashByOffset',
|
||||
requestID,
|
||||
offset,
|
||||
count,
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
/* signature: sm2.doSignature(
|
||||
id + '|' + sm2Key.publicKey,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
), */
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
loadNodeConfig(): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'loadNodeConfig',
|
||||
requestID,
|
||||
|
||||
...(sm2Key
|
||||
? {
|
||||
pubkey: sm2Key.publicKey,
|
||||
signature: sm2.doSignature(sm2Key.publicKey, sm2Key.privateKey, {
|
||||
hash: true,
|
||||
der: true,
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
queryUserStat(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'queryUserStat',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
listNodes(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'listNodes',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
killContractProcess(id: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'killContractProcess',
|
||||
requestID,
|
||||
id,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
distributeYPK(projectName: string, nodeIDs: string): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'distributeYPK',
|
||||
requestID,
|
||||
pubKey: sm2Key.publicKey,
|
||||
projectName,
|
||||
nodeIDs,
|
||||
signature: sm2.doSignature(
|
||||
`DistributeYPK|${projectName}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
{ hash: true, der: true },
|
||||
),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
listYPKs(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'listYPKs',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
deleteFile(file: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'deleteFile',
|
||||
requestID,
|
||||
file,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
startContractByYPK(project: string): Promise<ResponseData> {
|
||||
const sm2Key = this.sm2Key
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'startContractByYPK',
|
||||
isPrivate: true,
|
||||
requestID,
|
||||
owner: sm2Key.publicKey,
|
||||
path: `/${project}`,
|
||||
signature: sm2.doSignature(
|
||||
`Fixed|${project}|${sm2Key.publicKey}`,
|
||||
sm2Key.privateKey,
|
||||
),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
initBDServer(
|
||||
host: string,
|
||||
username: string,
|
||||
password: string,
|
||||
name: string,
|
||||
clusterHost: string,
|
||||
): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'initBDServer',
|
||||
requestID,
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
name,
|
||||
sm2Key: JSON.stringify(this.sm2Key),
|
||||
clusterHost,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
initBDCluster(
|
||||
host: string,
|
||||
username: string,
|
||||
password: string,
|
||||
name: string,
|
||||
sm2Key: string,
|
||||
agents: [],
|
||||
): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'initBDCluster',
|
||||
requestID,
|
||||
host,
|
||||
username,
|
||||
password,
|
||||
name,
|
||||
sm2Key,
|
||||
agents,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
listCompiledFiles(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'listCompiledFiles',
|
||||
requestID,
|
||||
isPrivate: true,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getManagerPubkey(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getManagerPubkey',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
getClusterName(): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'getClusterName',
|
||||
requestID,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
|
||||
setClusterName(name: string): Promise<ResponseData> {
|
||||
const requestID = `${new Date().getTime()}_${Math.floor(
|
||||
Math.random() * 10000,
|
||||
)}`
|
||||
const request = {
|
||||
action: 'setClusterName',
|
||||
requestID,
|
||||
name,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(request))
|
||||
return new Promise((resolve, reject) => {
|
||||
this.promiseCallbackPairs[requestID] = { resolve, reject }
|
||||
})
|
||||
}
|
||||
}
|
143
src/wssocket.ts
Normal file
143
src/wssocket.ts
Normal file
@ -0,0 +1,143 @@
|
||||
/* eslint-disable no-console,no-cond-assign */
|
||||
|
||||
export interface WsEvent {
|
||||
data: string
|
||||
}
|
||||
|
||||
export type OnOpenHandler = (this: WebSocket, ev: Event) => void
|
||||
export type WsHandler = (ev: WsEvent, ws?: WebSocket) => void
|
||||
|
||||
interface SegmentData {
|
||||
action: 'sendSeg'
|
||||
cid: string
|
||||
data: string
|
||||
}
|
||||
|
||||
export class WsSocket {
|
||||
private handlerList: WsHandler[] = []
|
||||
private toSend = ''
|
||||
private isSending = false
|
||||
private sendList: string[] = []
|
||||
private toReceive = ''
|
||||
private wssocket: WebSocket
|
||||
|
||||
constructor(wsurl: string, onopen: OnOpenHandler, handler?: WsHandler) {
|
||||
console.log(`[createWS.js] createWssocket : ${wsurl}`)
|
||||
if (handler) {
|
||||
this.handlerList.push(handler)
|
||||
}
|
||||
|
||||
// TODO: we don't need monitor at all?
|
||||
this.monitor()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const that = this
|
||||
|
||||
const wssocket = (this.wssocket = new WebSocket(wsurl))
|
||||
wssocket.onerror = function (error): void {
|
||||
console.log(error)
|
||||
}
|
||||
wssocket.onopen = onopen
|
||||
|
||||
const onmessage = function (this: WebSocket, event: MessageEvent): void {
|
||||
const obj = JSON.parse(event.data as string) as { action: string }
|
||||
switch (obj.action) {
|
||||
case 'sendNextSegment':
|
||||
that.sendNextSegment()
|
||||
break
|
||||
case 'sendSeg':
|
||||
that.receiveSeg(obj as SegmentData)
|
||||
break
|
||||
default:
|
||||
that.handlerList.forEach((h) => h(event, this))
|
||||
}
|
||||
}
|
||||
wssocket.onmessage = onmessage
|
||||
|
||||
const reconnect = function (): void {
|
||||
setTimeout(() => {
|
||||
console.log('[createWS.js] try to reconnect')
|
||||
const wssocket = (that.wssocket = new WebSocket(wsurl))
|
||||
wssocket.onclose = reconnect
|
||||
wssocket.onmessage = onmessage
|
||||
wssocket.onopen = onopen
|
||||
}, 1000)
|
||||
}
|
||||
wssocket.onclose = reconnect
|
||||
}
|
||||
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'] {
|
||||
return this.wssocket.readyState
|
||||
}
|
||||
|
||||
sendNextSegment(): void {
|
||||
const str = this.toSend
|
||||
if (str.length > 1024) {
|
||||
this.toSend = str.substr(1024)
|
||||
const obj = {
|
||||
isSegment: true,
|
||||
data: str.substr(0, 1024),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(obj))
|
||||
} else {
|
||||
this.toSend = ''
|
||||
const obj = {
|
||||
isSegment: false,
|
||||
data: str,
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(obj))
|
||||
this.isSending = false
|
||||
let data
|
||||
if ((data = this.sendList.pop())) {
|
||||
this.send(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receiveSeg(obj: SegmentData): void {
|
||||
if (obj.cid === 'start') {
|
||||
this.toReceive = ''
|
||||
}
|
||||
this.toReceive += obj.data
|
||||
if (obj.cid === 'done') {
|
||||
console.log(`[receiveSeg] Received AllData:${this.toReceive}`)
|
||||
const event: WsEvent = {
|
||||
data: this.toReceive,
|
||||
}
|
||||
this.toReceive = ''
|
||||
this.handlerList.forEach((h) => h(event, this.wssocket))
|
||||
}
|
||||
}
|
||||
|
||||
monitor(): void {
|
||||
if (!this.isSending) {
|
||||
let data
|
||||
if ((data = this.sendList.pop())) {
|
||||
this.send(data)
|
||||
}
|
||||
}
|
||||
setTimeout(() => this.monitor(), 1000)
|
||||
}
|
||||
|
||||
send(data: string): void {
|
||||
if (this.isSending) {
|
||||
this.sendList.push(data)
|
||||
return
|
||||
}
|
||||
if (data.length > 1024) {
|
||||
this.isSending = true
|
||||
this.toSend = data.substr(1024)
|
||||
const obj = {
|
||||
isSegment: true,
|
||||
data: data.substr(0, 1024),
|
||||
}
|
||||
this.wssocket.send(JSON.stringify(obj))
|
||||
} else {
|
||||
this.wssocket.send(data)
|
||||
}
|
||||
}
|
||||
|
||||
addHandler(handler: WsHandler): void {
|
||||
this.handlerList.push(handler)
|
||||
}
|
||||
}
|
91
test-node/http.html
Normal file
91
test-node/http.html
Normal file
@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="./sm2.js"></script>
|
||||
<script src="./cryptico.iife.js"></script>
|
||||
<script src="../lib/index.js"></script>
|
||||
<script>
|
||||
console.log(11)
|
||||
function print(string) {
|
||||
document.write(`${string}\n\n`)
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
console.log(33)
|
||||
const url = 'https://041.node.internetapi.cn:21030/SCIDE'
|
||||
// const url = 'http://022.node.internetapi.cn:18010/SCIDE'
|
||||
// const url = 'http://39.104.201.40:18010/NodeCenter'
|
||||
// const url = 'http://localhost/8080/api/sse'
|
||||
// eslint-disable-next-line no-undef
|
||||
const sm2Key = {
|
||||
privateKey:
|
||||
'd675782acf011dbc01a73c7967ccff9564486f7c3a9f5d5de151caffaa18936',
|
||||
publicKey:
|
||||
'04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
|
||||
// '04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
|
||||
}
|
||||
// eslint-disable-next-line no-undef
|
||||
const client = new bdcontract.HttpClient(url, sm2Key)
|
||||
|
||||
// await client.authNodeRole(true,'0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a')
|
||||
// const dataa = [
|
||||
// {
|
||||
// nodeName: '18000',
|
||||
// pubKey:
|
||||
// '041016acfbc8f4068a24d38a99a1355449ba958f7e905d66617cec9eda311e3001f8d15a4440b6eb61d7b7bd94bb434b30a518623c1593540e7d32eb72fe8088e1',
|
||||
// },
|
||||
// ]
|
||||
// await client.createTrustUnit(dataa, '12345')
|
||||
// const data = client.startContractByYPK({
|
||||
// // signature:
|
||||
// // '3045022100e13a8a1493ebbbb31e0b4d387ea061fd73a362b1e9fa0000066e87c5e9612907022037e04cb5ffa31fca23260a144eff2cbc8c04f6aac5be0d141609da4c66be3996',
|
||||
// isPrivate: true,
|
||||
// script: `contract shorgc\\n{ \\nexport function hello(){return 1 } }`,
|
||||
// path: '/data/tmp/hello.ypk',
|
||||
// })
|
||||
// 0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a
|
||||
// 调用合约
|
||||
// const data = client.executeContract('ControlProxy', 'getDoList', 'ss', false)
|
||||
// const data = await client.applyRole('NodeManager')
|
||||
// const data = await client.applyNodeRole('ContractInstanceManager')
|
||||
const data = await client.applyNodeRole('ContractInstanceManager')
|
||||
console.log(data, 'data')
|
||||
// const data = client.startContractMultiPoint(
|
||||
// '041016acfbc8f4068a24d38a99a1355449ba958f7e905d66617cec9eda311e3001f8d15a4440b6eb61d7b7bd94bb434b30a518623c1593540e7d32eb72fe8088e1,04a1bcfe25e973691fb055c5400d74cd722f05313149a89b9ae94fffe8a3f141a36193c43bf520f8260cac1a703a3b8f1f92e9c7c23ce61ef9a0cbecf670b07212,04870d138f9e6ffae2a0ae0b495c6d81ff6cca9c92c861156d7a5304558427588e05452394ce69c4894283d1b0ccf40ffdffbd13fa0884d9e559c355ac1672263b,',
|
||||
// 6,
|
||||
// 3,ß
|
||||
// 'H2_2022-07-12-12_48_55_Auto.ypk',
|
||||
// false,
|
||||
// '',
|
||||
// )
|
||||
// const data = client.updateConfig('nodeName','Node_180')
|
||||
// const code = `contract shorgc\\n{ \\nexport function hello(){return 1 } }`
|
||||
// const data = client.startContract(code)
|
||||
// const data = client.saveFile({
|
||||
// content: 's',
|
||||
// isAppend: false,
|
||||
// isPrivate: true,
|
||||
// path: '/data/tmp/hello.ypk',
|
||||
// })
|
||||
// const data = client.loadNodeConfig()
|
||||
// const data = client.listContractProcess()
|
||||
// const data = client.listNodes()
|
||||
// const data = client.distributeContract(
|
||||
// '0495d91b4dec0d14b067e8a3bd5d78f53f1389920284c0153547d9417ed37708f276e8ac3d8420e571106c9ab2c210192dd356b9757ea498fe578e5cc85182712e,',
|
||||
// 'DoipDist-0.1.0.ypk',
|
||||
// false,
|
||||
// '04d1924329f72ced148f6f333fb985ccbaa31b1e3aacf10be5f43d4a4ff5ad88899a005e79e37fc06993e1d66ada8cf8b711cb36f59538bb',
|
||||
// )
|
||||
// const data = client.killContractProcess('1759263594')
|
||||
// const data = client.killAllContract()
|
||||
print(JSON.stringify(data))
|
||||
})()
|
||||
// console.log(data)
|
||||
</script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
103
test-node/index.js
Normal file
103
test-node/index.js
Normal file
@ -0,0 +1,103 @@
|
||||
const bdcontract = require('@bdcontract/sdk')
|
||||
// const sm2 = require('sm-crypto')
|
||||
// import { sm2 } from 'sm-crypto'
|
||||
async function main() {
|
||||
// const url = 'http://localhost:21030/SCIDE'
|
||||
const url = 'http://39.104.201.40:18010/SCIDE'
|
||||
// const url = 'http://39.104.201.40:18010/NodeCenter'
|
||||
// const url = 'http://021.node.internetapi.cn:18060/NodeCenter'
|
||||
// const url = 'http://localhost/8080/api/sse'
|
||||
// eslint-disable-next-line no-undef
|
||||
const sm2Key = {
|
||||
publicKey:
|
||||
'04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
|
||||
privateKey:
|
||||
'd675782acf011dbc01a73c7967ccff9564486f7c3a9f5d5de151caffaa18936',
|
||||
}
|
||||
|
||||
// const keyPair = sm2.generateKeyPairHex()
|
||||
|
||||
// const url1 = 'http://023.node.internetapi.cn:18010/SCIDE/SCManager'
|
||||
// const url1 = 'http://023.node.internetapi.cn:18010/SCIDE/SCManager?action=applyNodeRole&role=ContractProvider&pubKey=04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27&sign=3046022100d186df39542f44deb08ca9a6a33ea4c0eef4222c3d0a9821e836a231daa615fa022100d89b202b3bb44c8caf98b3c415c62359eab2607c391ad04ba39034a550a78db3'
|
||||
// const res1 = await fetch(url1)
|
||||
// console.log(res1)
|
||||
// const res2 = await fetch(url1)
|
||||
// console.log(res2)
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const client = new bdcontract.HttpClient(url, sm2Key, { timeout: 20000 })
|
||||
|
||||
try {
|
||||
// const result = await client.executeContract(
|
||||
// 'ControlProxy',
|
||||
// 'setName',
|
||||
// { name: 'df' },
|
||||
// 'POST',
|
||||
// true,
|
||||
// )
|
||||
// const result = await client.updateConfig('dataChain', 'ddsjkdsf')
|
||||
// const result = await client.resetNodeManager()
|
||||
// const result = await client.applyNodeRole('ContractProvider')
|
||||
// const result = await client.loadNodeConfig()
|
||||
// const result = await client.configContract({
|
||||
// nodeName: 'test',
|
||||
// bdledgerAddr: 'bdledger:2401',
|
||||
// masterAddr: 'localhost:21030',
|
||||
// contractCenterAddr: 'localhost:21040',
|
||||
// // 配置中心节点时使用
|
||||
// LHSProxyAddress: 'http://localhost:21041',
|
||||
// })
|
||||
// console.log(result, 'res1')
|
||||
|
||||
const result = await client.executeContract(
|
||||
'ControlProxy',
|
||||
'getDoList',
|
||||
1,
|
||||
true,
|
||||
)
|
||||
console.log(result, 'res1')
|
||||
} catch (e) {
|
||||
console.log('error: ', e.message)
|
||||
}
|
||||
|
||||
// const res2 = await client.applyNodeRole('ContractInstanceManager')
|
||||
// console.log(res2.data, 'res2')
|
||||
// const res2 = await client.authNodeManager(
|
||||
// true,
|
||||
// '0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a',
|
||||
// )
|
||||
// // const res3 = await client.applyRole('NodeManager')
|
||||
// console.log(res2, 'res2res2res2res2res2res2res2res2res2res2res2')
|
||||
// const res3 = await client.applyNodeRole(
|
||||
// '0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a',
|
||||
// 'ContractInstanceManager',
|
||||
// )
|
||||
// console.log(res3, 'res33333333333333333333333333333333')
|
||||
// // console.log(res1.data, 'data')
|
||||
// const res1 = await client.authNodeRole(
|
||||
// true,
|
||||
// '0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a',
|
||||
// )
|
||||
// console.log(res1, 'res11111111111111111111111111111111')
|
||||
// console.log(res1.data, 'data')
|
||||
|
||||
// const res1 = await client.applyRole('ContractProvider')
|
||||
// console.log(res1, 'res')
|
||||
// console.log(res1.data, 'data')
|
||||
|
||||
// let i = 0
|
||||
// for (i = 0; i < 3000000000; i++) {
|
||||
// a = i + 1
|
||||
// if (a > 100000000000000) {
|
||||
// console.log('b')
|
||||
// }
|
||||
// }
|
||||
|
||||
// setTimeout(async ()=> {
|
||||
// const client2 = new bdcontract.HttpClient(url, sm2Key)
|
||||
// const res2 = await client.applyNodeRole('ContractInstanceManager')
|
||||
// console.log(res2)
|
||||
// }, 1)
|
||||
}
|
||||
|
||||
void main().then(console.log)
|
9
test-node/package.json
Normal file
9
test-node/package.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@bdcontract/sdk": "link:..",
|
||||
"@formily/core": "^2.2.5",
|
||||
"@formily/element-plus": "1.0.0-beta.6",
|
||||
"@formily/vue": "^2.2.5",
|
||||
"@vue/composition-api": "^1.7.1"
|
||||
}
|
||||
}
|
18
test-node/tsconfig.json
Normal file
18
test-node/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"lib": ["esnext", "dom", "dom.iterable"],
|
||||
"moduleResolution": "Node",
|
||||
"types": ["node"],
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"noEmit": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true
|
||||
}
|
||||
}
|
2
test/cryptico.iife.js
Normal file
2
test/cryptico.iife.js
Normal file
File diff suppressed because one or more lines are too long
1
test/cryptico.iife.js.map
Normal file
1
test/cryptico.iife.js.map
Normal file
File diff suppressed because one or more lines are too long
110
test/http.html
Normal file
110
test/http.html
Normal file
@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- <script src="../node_modules/cross-fetch/dist/cross-fetch.js"></script> -->
|
||||
<script src="../lib/index.js"></script>
|
||||
<script src="./sm2.js"></script>
|
||||
<script src="./cryptico.iife.js"></script>
|
||||
<!-- <script src="../dist/bdcontract-sdk.iife.js"></script> -->
|
||||
<script>
|
||||
function print(string) {
|
||||
document.write(`${string}\n\n`)
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
// const url = 'http://021.node.internetapi.cn:18010/SCIDE'
|
||||
// const url = 'http://022.node.internetapi.cn:18010/SCIDE'
|
||||
const url = 'http://041.node.internetapi.cn:21030/SCIDE/SCIDE'
|
||||
// const url = 'http://localhost/8080/api/sse'
|
||||
|
||||
const sm2Key = {
|
||||
privateKey:
|
||||
'd675782acf011dbc01a73c7967ccff9564486f7c3a9f5d5de151caffaa18936',
|
||||
publicKey:
|
||||
'04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
|
||||
// '04303718771b9323c204e607639f14469f9a94e55b0964a408ad3b3864b0493b645d7070da0d550f0c54b934275a8e88dedc3024467b0566db5c1108b1baeaae27',
|
||||
}
|
||||
// eslint-disable-next-line no-undef
|
||||
const client = new bdcontract.HttpClient(url, sm2Key)
|
||||
|
||||
const data = await client.executeContract(
|
||||
'ControlProxy',
|
||||
'getDoList',
|
||||
1,
|
||||
true,
|
||||
)
|
||||
// await client.applyNodeRole('ContractProvider')
|
||||
// await client.applyNodeRole('ContractInstanceManager')
|
||||
// const data = await client.authNodeRole(
|
||||
// true,
|
||||
// '0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a',
|
||||
// )
|
||||
// await client.authNodeRole(true,'0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a')
|
||||
// const dataa = [
|
||||
// {
|
||||
// nodeName: '18000',
|
||||
// pubKey:
|
||||
// '041016acfbc8f4068a24d38a99a1355449ba958f7e905d66617cec9eda311e3001f8d15a4440b6eb61d7b7bd94bb434b30a518623c1593540e7d32eb72fe8088e1',
|
||||
// },
|
||||
// ]
|
||||
// await client.createTrustUnit(dataa, '12345')
|
||||
// const data = client.startContractByYPK({
|
||||
// // signature:
|
||||
// // '3045022100e13a8a1493ebbbb31e0b4d387ea061fd73a362b1e9fa0000066e87c5e9612907022037e04cb5ffa31fca23260a144eff2cbc8c04f6aac5be0d141609da4c66be3996',
|
||||
// isPrivate: true,
|
||||
// script: `contract shorgc\\n{ \\nexport function hello(){return 1 } }`,
|
||||
// path: '/data/tmp/hello.ypk',
|
||||
// })
|
||||
// 0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a
|
||||
// 调用合约
|
||||
// const data = client.executeContract('ControlProxy', 'getDoList', 'ss', false)
|
||||
// const data = await client.applyNodeRole(
|
||||
// '0430276215ff414e0047a532d4dea32048ad4ec60a729ce8e4248c98889d244c3b27b9549e5cb664ce324e2acac4a81590321f4196ca159cb577e06a3eb553ce6a',
|
||||
// 'ContractProvider',
|
||||
// )
|
||||
// const data = await client.applyNodeRole('ContractInstanceManager')
|
||||
|
||||
// const data = client.startContractMultiPoint(
|
||||
// '041016acfbc8f4068a24d38a99a1355449ba958f7e905d66617cec9eda311e3001f8d15a4440b6eb61d7b7bd94bb434b30a518623c1593540e7d32eb72fe8088e1,04a1bcfe25e973691fb055c5400d74cd722f05313149a89b9ae94fffe8a3f141a36193c43bf520f8260cac1a703a3b8f1f92e9c7c23ce61ef9a0cbecf670b07212,04870d138f9e6ffae2a0ae0b495c6d81ff6cca9c92c861156d7a5304558427588e05452394ce69c4894283d1b0ccf40ffdffbd13fa0884d9e559c355ac1672263b,',
|
||||
// 6,
|
||||
// 3,ß
|
||||
// 'H2_2022-07-12-12_48_55_Auto.ypk',
|
||||
// false,
|
||||
// '',
|
||||
// )
|
||||
// const data = client.updateConfig('nodeName','Node_180')
|
||||
// const code = `contract shorgc\\n{ \\nexport function hello(){return 1 } }`
|
||||
// const data = client.startContract(code)
|
||||
// const data = client.saveFile({
|
||||
// content: 's',
|
||||
// isAppend: false,
|
||||
// isPrivate: true,
|
||||
// path: '/data/tmp/hello.ypk',
|
||||
// })
|
||||
// const data = client.loadNodeConfig()
|
||||
// const data = client.listContractProcess()
|
||||
// const data = client.listNodes()
|
||||
// const data = client.distributeContract(
|
||||
// '0495d91b4dec0d14b067e8a3bd5d78f53f1389920284c0153547d9417ed37708f276e8ac3d8420e571106c9ab2c210192dd356b9757ea498fe578e5cc85182712e,',
|
||||
// 'DoipDist-0.1.0.ypk',
|
||||
// false,
|
||||
// '04d1924329f72ced148f6f333fb985ccbaa31b1e3aacf10be5f43d4a4ff5ad88899a005e79e37fc06993e1d66ada8cf8b711cb36f59538bb',
|
||||
// )
|
||||
// const data = client.killContractProcess('1759263594')
|
||||
// const data = client.killAllContract()
|
||||
// const data = await client.downloadContract(
|
||||
// 'r',
|
||||
// false,
|
||||
// new Date().getTime(),
|
||||
// )
|
||||
print(JSON.stringify(data))
|
||||
})()
|
||||
// console.log(data)
|
||||
</script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
2102
test/sm2.js
Normal file
2102
test/sm2.js
Normal file
File diff suppressed because it is too large
Load Diff
51
test/ws.html
Normal file
51
test/ws.html
Normal file
@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<script src="./sm2.js"></script>
|
||||
<script src="./cryptico.iife.js"></script>
|
||||
<script src="../lib/index.js"></script>
|
||||
<script>
|
||||
function print(string) {
|
||||
document.write(`${string}\n\n`)
|
||||
}
|
||||
|
||||
const url = 'ws://39.104.201.40:18010/SCIDE/SCExecutor'
|
||||
|
||||
const client = new bdcontract.WsClient(
|
||||
url,
|
||||
(ev) => {
|
||||
console.log(JSON.stringify(ev))
|
||||
},
|
||||
(ev, ws) => {
|
||||
console.log(ev.data)
|
||||
},
|
||||
)
|
||||
setTimeout(async () => {
|
||||
const status = client.status()
|
||||
console.log(status)
|
||||
try {
|
||||
let data = await client.executeContract(
|
||||
'AnnotationExample0608',
|
||||
'main',
|
||||
'abacd',
|
||||
)
|
||||
print(JSON.stringify(data))
|
||||
|
||||
data = await client.executeContract(
|
||||
'NonExistentContract',
|
||||
'random',
|
||||
'abacd',
|
||||
)
|
||||
print(JSON.stringify(data))
|
||||
} catch (data) {
|
||||
print(JSON.stringify(data))
|
||||
}
|
||||
}, 1000)
|
||||
</script>
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
10
tsconfig.build.json
Normal file
10
tsconfig.build.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"declaration": true,
|
||||
"declarationDir": "types",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"exclude": ["test/**/*.ts", "test/**/*.d.ts", "rollup.config.ts"]
|
||||
}
|
26
tsconfig.json
Normal file
26
tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"lib": ["esnext", "dom", "dom.iterable"],
|
||||
"moduleResolution": "Node",
|
||||
"types": ["node"],
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"noEmit": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"test/**/*.ts",
|
||||
"test/**/*.d.ts",
|
||||
"rollup.config.ts"
|
||||
],
|
||||
"exclude": ["src/**/*.js", "test/**/*.js"]
|
||||
}
|
16
types/crypto.d.ts
vendored
Normal file
16
types/crypto.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
import type { AESKey } from '@daotl/cryptico';
|
||||
import { RSAKey } from '@daotl/cryptico';
|
||||
export declare function aesEncrypt(data: string, aesKey: AESKey): string;
|
||||
export declare function rsaEncrypt(data: string, rsaKey: {
|
||||
n: string;
|
||||
e1: string;
|
||||
}): string;
|
||||
export declare function loadRSAKey(rsaKey: string): RSAKey;
|
||||
export declare function encryptReq(reqContent: {
|
||||
contractID: string;
|
||||
}, pubKey: RSAKey): {
|
||||
action: string | null;
|
||||
contractID: string;
|
||||
arg: string;
|
||||
requester: string;
|
||||
};
|
56
types/httpClient.d.ts
vendored
Normal file
56
types/httpClient.d.ts
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
import { type AxiosRequestConfig } from 'axios';
|
||||
import type { KeyPairHex } from 'sm-crypto';
|
||||
import type { ClientResponse, ConfigNodeArgs, ExecuteContractArgs, ListAllUsersResponseData, ListNodesResponse, ListProjectPermissionRequest, ListProjectPermissionResponseData, LoadNodeConfigResponseData, ExecuteContractResponse, PingResponse, SaveFileRequest, StartContractByYpkRequest } from './types';
|
||||
export * from './types';
|
||||
export declare class HttpClient {
|
||||
private baseUrl;
|
||||
private sm2Key;
|
||||
private fetch;
|
||||
constructor(baseUrl: string, sm2Key: KeyPairHex, config?: AxiosRequestConfig<any>);
|
||||
requestWithSignature<Data>(path: string, init?: Partial<RequestInit>, sm2Key?: KeyPairHex): Promise<ClientResponse<Data>>;
|
||||
retryRequestWithSignature<Data>(retryTimes: number, path: string, init?: Partial<RequestInit>, sm2Key?: KeyPairHex): Promise<ClientResponse<Data>>;
|
||||
sign(data: string, privateKey?: string): string;
|
||||
ping(): Promise<PingResponse>;
|
||||
startContract(code: string): Promise<ClientResponse<string>>;
|
||||
startContractByYPK(_request: StartContractByYpkRequest): Promise<ClientResponse<string>>;
|
||||
executeContract(contractID: string, operation: string, arg: string, { method, withDynamicAnalysis, withSignature, }?: ExecuteContractArgs): Promise<ClientResponse<ExecuteContractResponse<string>>>;
|
||||
killContractProcess(contractID: string, requestID?: string): Promise<ClientResponse<string>>;
|
||||
killAllContract(): Promise<ClientResponse<string>>;
|
||||
applyNodeRole(role: string): Promise<ClientResponse<{
|
||||
action: string;
|
||||
data: string;
|
||||
role?: string;
|
||||
}>>;
|
||||
authNodeRole(isAccept: boolean, authorizedPubKey: string, managerPair?: KeyPairHex): Promise<ClientResponse<{
|
||||
action: string;
|
||||
data: string;
|
||||
}>>;
|
||||
distributeContract(nodeIDs: string, projectName: string, isPrivate: boolean): void;
|
||||
saveFile(_request: SaveFileRequest): Promise<ClientResponse<string>>;
|
||||
listProjectPermission(_request: ListProjectPermissionRequest): Promise<ClientResponse<ListProjectPermissionResponseData>>;
|
||||
startContractMultiPoint(peersID: string, type: number, selectUnitNum: number, projectName: string, isPrivate: boolean, sponsorPeerID: string): Promise<ClientResponse<string>>;
|
||||
loadNodeConfig(): Promise<ClientResponse<LoadNodeConfigResponseData>>;
|
||||
updateConfig(key: string, val: string): Promise<ClientResponse<boolean>>;
|
||||
resetNodeManager(): Promise<boolean>;
|
||||
lockEdit(): Promise<ClientResponse<string>>;
|
||||
unlockEdit(): Promise<ClientResponse<string>>;
|
||||
addNode(nodePubKey: string): Promise<ClientResponse<string>>;
|
||||
applyRole(role: string): Promise<ClientResponse<string>>;
|
||||
authNodeManager(isAccept: boolean, authorizedPubKey: string): Promise<ClientResponse<string>>;
|
||||
listAllUsers(): Promise<ClientResponse<ListAllUsersResponseData>>;
|
||||
listNodes(): Promise<ListNodesResponse>;
|
||||
createTrustUnit(data: {
|
||||
nodeName: string;
|
||||
pubkey: string;
|
||||
}[], Msg: string): Promise<{
|
||||
action: string;
|
||||
status: string;
|
||||
}>;
|
||||
listTrustUnits(): Promise<ClientResponse<{
|
||||
key: string;
|
||||
value: string;
|
||||
}[]>>;
|
||||
listContractProcess(): Promise<ClientResponse<string>>;
|
||||
downloadContract(projectName: string, isPrivate: boolean, timestamp: number): Promise<ClientResponse<string>>;
|
||||
configNode(args: ConfigNodeArgs): Promise<boolean>;
|
||||
}
|
4
types/index.d.ts
vendored
Normal file
4
types/index.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './crypto';
|
||||
export * from './httpClient';
|
||||
export * from './wsClient';
|
||||
export * from './wssocket';
|
84
types/types.d.ts
vendored
Normal file
84
types/types.d.ts
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
export type ClientResponse<Data> = Omit<Response, 'data'> & {
|
||||
data?: Data;
|
||||
};
|
||||
export type PingResponse = ClientResponse<'pong'>;
|
||||
export interface SaveFileRequest {
|
||||
content: string;
|
||||
isAppend: boolean;
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
}
|
||||
export interface ListProjectPermissionRequest {
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
}
|
||||
export interface ListProjectPermissionResponseData {
|
||||
permissions: string[];
|
||||
ypk: string;
|
||||
}
|
||||
export interface StartContractByYpkRequest {
|
||||
isPrivate: boolean;
|
||||
path: string;
|
||||
script: string;
|
||||
}
|
||||
export interface ListAllUsersResponseDataListItem {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
export interface ListAllUsersResponseData {
|
||||
kv: ListAllUsersResponseDataListItem[];
|
||||
time: ListAllUsersResponseDataListItem[];
|
||||
}
|
||||
export interface OnlineContractsItem {
|
||||
contractID: string;
|
||||
contractName: string;
|
||||
isMaster: boolean;
|
||||
type: string;
|
||||
yjsType: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
export interface OnlineItem {
|
||||
cimanager: string;
|
||||
contractVersion: number;
|
||||
events: number;
|
||||
ipPort: string;
|
||||
masterAddress: string;
|
||||
nodeName: string;
|
||||
peerID: string;
|
||||
pubKey: string;
|
||||
contracts: OnlineContractsItem[];
|
||||
}
|
||||
export interface ListNodesResponse {
|
||||
action: string;
|
||||
offline: string[];
|
||||
online: OnlineItem[];
|
||||
}
|
||||
export interface DistributeContractResponse {
|
||||
action: string;
|
||||
progress: string;
|
||||
}
|
||||
export interface ExecuteContractArgs extends RequestInit {
|
||||
method?: 'POST' | 'GET';
|
||||
withSignature?: boolean;
|
||||
withDynamicAnalysis?: boolean;
|
||||
}
|
||||
export interface ExecuteContractResponse<Data> {
|
||||
status?: boolean;
|
||||
data?: Data;
|
||||
executeTime?: number;
|
||||
cid?: string;
|
||||
isPrivate?: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
export interface ConfigNodeArgs {
|
||||
nodeName?: string;
|
||||
dataChain?: string;
|
||||
masterAddress?: string;
|
||||
nodeCenter?: string;
|
||||
LHSProxyAddress?: string;
|
||||
[K: string]: string | undefined;
|
||||
}
|
||||
export interface LoadNodeConfigResponseData {
|
||||
doipConfig: string;
|
||||
[K: string]: string;
|
||||
}
|
56
types/wsClient.d.ts
vendored
Normal file
56
types/wsClient.d.ts
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
import type { KeyPairHex } from 'sm-crypto';
|
||||
import type { OnOpenHandler, WsHandler } from './wssocket';
|
||||
interface ResponseData {
|
||||
action: string;
|
||||
responseID?: string;
|
||||
status: true | false | string;
|
||||
result?: unknown;
|
||||
data: string;
|
||||
[K: string]: unknown;
|
||||
}
|
||||
export declare class WsClient {
|
||||
private readonly sm2Key;
|
||||
private readonly wssocket;
|
||||
private readonly promiseCallbackPairs;
|
||||
private readonly sessionPromise;
|
||||
private sessionResolve;
|
||||
private readonly loginPromise;
|
||||
private loginResolve;
|
||||
constructor(url: string, onopen: OnOpenHandler, handler: WsHandler, sm2Key?: KeyPairHex);
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'];
|
||||
sessionReceived(): Promise<string>;
|
||||
login(): Promise<boolean>;
|
||||
loggedIn(): Promise<boolean>;
|
||||
matchCID(contractID: string): Promise<ResponseData>;
|
||||
getMetabyCID(contractID: string): Promise<ResponseData>;
|
||||
getMetabyReadme(keyword: string, page?: string, pageSize?: string): Promise<ResponseData>;
|
||||
getMetabyPubkey(pubkey: string): Promise<ResponseData>;
|
||||
segmentWord(words: string): Promise<ResponseData>;
|
||||
getMetabyOwner(owner: string, page?: string, pageSize?: string): Promise<ResponseData>;
|
||||
getDependentContract(contractName: string): Promise<ResponseData>;
|
||||
queryContractLogByDate(start: number): Promise<ResponseData>;
|
||||
queryDataByHash(hash: string): Promise<ResponseData>;
|
||||
executeContract(contractID: string, method: string, arg: unknown): Promise<ResponseData>;
|
||||
getSessionID(): Promise<ResponseData>;
|
||||
listTheContractProcess(contractID: string): Promise<ResponseData>;
|
||||
getMask(contractID: string): Promise<ResponseData>;
|
||||
setMask(contractID: string, operation: string, arg: string): Promise<ResponseData>;
|
||||
getMock(contractID: string): Promise<ResponseData>;
|
||||
setMock(contractID: string, operation: string, arg: string): Promise<ResponseData>;
|
||||
queryHashByOffset(offset: number, count: number): Promise<ResponseData>;
|
||||
loadNodeConfig(): Promise<ResponseData>;
|
||||
queryUserStat(): Promise<ResponseData>;
|
||||
listNodes(): Promise<ResponseData>;
|
||||
killContractProcess(id: string): Promise<ResponseData>;
|
||||
distributeYPK(projectName: string, nodeIDs: string): Promise<ResponseData>;
|
||||
listYPKs(): Promise<ResponseData>;
|
||||
deleteFile(file: string): Promise<ResponseData>;
|
||||
startContractByYPK(project: string): Promise<ResponseData>;
|
||||
initBDServer(host: string, username: string, password: string, name: string, clusterHost: string): Promise<ResponseData>;
|
||||
initBDCluster(host: string, username: string, password: string, name: string, sm2Key: string, agents: []): Promise<ResponseData>;
|
||||
listCompiledFiles(): Promise<ResponseData>;
|
||||
getManagerPubkey(): Promise<ResponseData>;
|
||||
getClusterName(): Promise<ResponseData>;
|
||||
setClusterName(name: string): Promise<ResponseData>;
|
||||
}
|
||||
export {};
|
26
types/wssocket.d.ts
vendored
Normal file
26
types/wssocket.d.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
export interface WsEvent {
|
||||
data: string;
|
||||
}
|
||||
export type OnOpenHandler = (this: WebSocket, ev: Event) => void;
|
||||
export type WsHandler = (ev: WsEvent, ws?: WebSocket) => void;
|
||||
interface SegmentData {
|
||||
action: 'sendSeg';
|
||||
cid: string;
|
||||
data: string;
|
||||
}
|
||||
export declare class WsSocket {
|
||||
private handlerList;
|
||||
private toSend;
|
||||
private isSending;
|
||||
private sendList;
|
||||
private toReceive;
|
||||
private wssocket;
|
||||
constructor(wsurl: string, onopen: OnOpenHandler, handler?: WsHandler);
|
||||
status(): WebSocket['CLOSED' | 'CLOSING' | 'CONNECTING' | 'OPEN'];
|
||||
sendNextSegment(): void;
|
||||
receiveSeg(obj: SegmentData): void;
|
||||
monitor(): void;
|
||||
send(data: string): void;
|
||||
addHandler(handler: WsHandler): void;
|
||||
}
|
||||
export {};
|
Loading…
Reference in New Issue
Block a user