2023-03-15 01:15:57 +08:00

742 lines
19 KiB
TypeScript

/* 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 }
})
}
}