@caict/bop-typescript-sdk
Version:
367 lines (326 loc) • 12.3 kB
text/typescript
import {
HelloResponse,
HelloResult,
GetAccountRequest,
GetAccountResponse,
GetAccountBaseRequest,
GetAccountBaseResponse,
GetAccountMetadataRequest,
GetAccountMetadataResponse,
GetLedgerRequest,
GetLedgerResponse,
SubmitTransactionRequest,
SubmitTransactionResponse,
GetTransactionHistoryRequest,
GetTransactionHistoryResponse,
TestTransactionRequest,
TestTransactionResponse,
CallContractRequest,
CallContractResponse,
QueryReturn,
QueryRequest,
QueryResponse,
QueryRequest_TxType,
GetTransactionCacheRequest,
GetTransactionCacheRequest_PoolType,
GetTransactionCacheChainResponse,
GetTransactionCachePlatResponse,
DiscardRequest,
DiscardResponse,
GetTxCacheSizeResponse,
GetTxCacheSizeResult,
StatusCodes,
} from "../bop-proto/bop";
import JSONbig from "json-bigint";
export class BaseService {
private readonly apiKey: string;
private readonly host: string;
private readonly apiSecret: string;
private readonly baseUrl: string;
private _hasApiSecret: boolean;
constructor(host: string, apiKey: string, apiSecret: string) {
this.host = host;
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseUrl = `${this.host}/base/${this.apiKey}`;
this._hasApiSecret = !(this.apiSecret === "");
}
private async fetchData(
endpoint: string,
params: any,
method: "GET" | "POST" = "GET",
timeout: number = 10000, // 默认超时时间为10秒
): Promise<any> {
// 创建一个AbortController实例
const controller = new AbortController();
const { signal } = controller;
// 设置一个超时
const timeoutId = setTimeout(() => {
controller.abort();
throw new Error("Request timed out");
}, timeout);
try {
let url = `${this.baseUrl}/${endpoint}`;
if (!url.startsWith("http://") && !url.startsWith("https://")) {
throw new Error("URL must start with 'http://' or 'https://'");
}
const headers = {
"Content-Type": "application/json",
...(this._hasApiSecret ? { "api-secret": this.apiSecret } : {}),
};
// 对params进行判断,如果是GET请求,则将params转为URL查询字符串并附加到URL上
let queryString = "";
if (method === "GET" && params) {
queryString = new URLSearchParams(params).toString();
if (queryString) {
url += `?${queryString}`;
}
}
// 创建body,仅在POST请求且params存在时创建
let body: string | null = null;
if (method === "POST" && params) {
body = JSON.stringify(params);
}
//console.log(url);
const response = await fetch(url, {
method,
headers,
body,
signal, // 将signal传递给fetch
});
if (!response.ok) {
throw new Error(
`HTTP error! Status: ${response.status}, Message: ${response.statusText}`,
);
}
const responseText = await response.text();
const data = JSONbig.parse(responseText);
clearTimeout(timeoutId); // 请求成功,清除超时计时器
return data;
} catch (error) {
clearTimeout(timeoutId); // 无论请求是否成功,都清除超时计时器
let errorDesc = "invalid url";
if (typeof error === "string") {
errorDesc = error;
} else if (error instanceof Error) {
errorDesc = error.message;
}
const obj = {
error_code: StatusCodes.URL_ERROR,
error_desc: errorDesc,
};
return obj;
}
}
public async hello(): Promise<HelloResponse> {
let helloResponse: HelloResponse;
helloResponse = HelloResponse.fromJSON(await this.fetchData("/hello", {}));
if (helloResponse.errorCode === 0) {
helloResponse.errorCode = 0;
helloResponse.errorDesc = "ok";
helloResponse.result = HelloResult.fromJSON(
await this.fetchData("/hello", {}),
);
helloResponse.success = true;
}
return helloResponse;
}
public async getAccount(
params: GetAccountRequest,
): Promise<GetAccountResponse> {
return GetAccountResponse.fromJSON(
await this.fetchData("/getAccount", params),
);
}
public async getAccountBase(
params: GetAccountBaseRequest,
): Promise<GetAccountBaseResponse> {
return GetAccountBaseResponse.fromJSON(
await this.fetchData("/getAccountBase", params),
);
}
public async getAccountMetaData(
params: GetAccountMetadataRequest,
): Promise<GetAccountMetadataResponse> {
return GetAccountMetadataResponse.fromJSON(
await this.fetchData("/getAccountMetaData", params),
);
}
public async getLedger(params: GetLedgerRequest): Promise<GetLedgerResponse> {
interface InternalGetLedgerRequest {
seq?: number;
with_validator?: boolean;
with_leader?: boolean;
}
let request: InternalGetLedgerRequest = {};
// 复制并转换 params 中的属性到 request 中
if (params.seq !== undefined) request.seq = params.seq;
if (params.withLeader !== undefined)
request.with_leader = params.withLeader;
if (params.withValidator !== undefined)
request.with_validator = params.withValidator;
return GetLedgerResponse.fromJSON(
await this.fetchData("/getLedger", request),
);
}
public async submitTransaction(
params: SubmitTransactionRequest,
): Promise<SubmitTransactionResponse> {
console.log(JSON.stringify(SubmitTransactionRequest.toJSON(params)));
return SubmitTransactionResponse.fromJSON(
await this.fetchData(
"/submitTransaction",
SubmitTransactionRequest.toJSON(params),
"POST",
),
);
}
public async getTransactionHistory(
params: GetTransactionHistoryRequest,
): Promise<GetTransactionHistoryResponse> {
interface InternalGetTransactionHistoryRequest {
hash?: string | undefined;
ledger_seq?: number | undefined;
start?: number | undefined;
limit?: number | undefined;
}
let request: InternalGetTransactionHistoryRequest = {};
if (params.hash !== undefined) request.hash = params.hash;
if (params.ledgerSeq !== undefined) request.ledger_seq = params.ledgerSeq;
if (params.start !== undefined) request.start = params.start;
if (params.limit !== undefined) request.limit = params.limit;
return GetTransactionHistoryResponse.fromJSON(
await this.fetchData("/getTransactionHistory", request),
);
}
public async testTransaction(
params: TestTransactionRequest,
): Promise<TestTransactionResponse> {
console.log(JSON.stringify(TestTransactionRequest.toJSON(params)));
return TestTransactionResponse.fromJSON(
await this.fetchData(
"/testTransaction",
TestTransactionRequest.toJSON(params),
"POST",
),
);
}
public async callContract(
params: CallContractRequest,
): Promise<CallContractResponse> {
params.optType = 2; //query
function parseCallContractResponse(data: any): CallContractResponse {
const queryRets: QueryReturn[] = (data.result?.query_rets || []).map(
(queryRet) => ({
error: JSON.stringify(queryRet.error), // 将error对象转换为字符串
result: queryRet.result ? JSON.stringify(queryRet.result) : undefined, // 将result对象转换为字符串(如果存在)
}),
);
return {
result: {
queryRets: queryRets.length > 0 ? queryRets : undefined, // 如果queryRets数组为空,则不设置该字段
},
success: data.success,
errorCode: data.error_code,
errorDesc: data.error_desc,
trace: data.trace,
};
}
return parseCallContractResponse(
await this.fetchData(
"/callContract",
CallContractRequest.toJSON(params),
"POST",
),
);
}
public async query(params: QueryRequest): Promise<QueryResponse> {
interface InternalQueryRequest {
bid?: string | undefined;
hash?: string | undefined;
tx_id?: string | undefined;
start_time?: string | undefined;
end_time?: string | undefined;
tx_type?: QueryRequest_TxType | undefined;
page?: number | undefined;
page_size?: number | undefined;
ledger_seq?: number | undefined;
}
let request: InternalQueryRequest = {};
if (params.bid !== undefined) request.bid = params.bid;
if (params.hash !== undefined) request.hash = params.hash;
if (params.txId !== undefined) request.tx_id = params.txId;
if (params.startTime !== undefined) request.start_time = params.startTime;
if (params.endTime !== undefined) request.end_time = params.endTime;
if (params.txType !== undefined) request.tx_type = params.txType;
if (params.page !== undefined) request.page = params.page;
if (params.pageSize !== undefined) request.page_size = params.pageSize;
if (params.ledgerSeq !== undefined) request.ledger_seq = params.ledgerSeq;
return QueryResponse.fromJSON(await this.fetchData("/query", request));
}
public async getTransactionCachePlat(
params: GetTransactionCacheRequest,
): Promise<GetTransactionCachePlatResponse> {
interface InternalGetTransactionCacheRequest {
pool_type?: GetTransactionCacheRequest_PoolType | undefined;
limit?: number | undefined;
hash?: string | undefined;
address?: string | undefined;
}
let request: InternalGetTransactionCacheRequest = {};
if (params.limit !== undefined) request.limit = params.limit;
if (params.hash !== undefined) request.hash = params.hash;
if (params.address !== undefined) request.address = params.address;
request.pool_type = GetTransactionCacheRequest_PoolType.PLATFORM;
return GetTransactionCachePlatResponse.fromJSON(
await this.fetchData("/getTransactionCache", request),
);
}
public async getTransactionCacheChain(
params: GetTransactionCacheRequest,
): Promise<GetTransactionCacheChainResponse> {
interface InternalGetTransactionCacheRequest {
pool_type?: GetTransactionCacheRequest_PoolType | undefined;
limit?: number | undefined;
hash?: string | undefined;
address?: string | undefined;
}
let request: InternalGetTransactionCacheRequest = {};
if (params.limit !== undefined) request.limit = params.limit;
if (params.hash !== undefined) request.hash = params.hash;
if (params.address !== undefined) request.address = params.address;
request.pool_type = GetTransactionCacheRequest_PoolType.CHAIN;
return GetTransactionCacheChainResponse.fromJSON(
await this.fetchData("/getTransactionCache", request),
);
}
public async discard(params: DiscardRequest): Promise<DiscardResponse> {
interface InternalDiscardResponse {
hash?: string | undefined;
page?: number | undefined;
page_size?: number | undefined;
}
let request: InternalDiscardResponse = {};
if (params.hash !== undefined) request.hash = params.hash;
if (params.page !== undefined) request.page = params.page;
if (params.pageSize !== undefined) request.page_size = params.pageSize;
return DiscardResponse.fromJSON(
await this.fetchData("/query/discard", request),
);
}
public async getTxCacheSize(): Promise<GetTxCacheSizeResponse> {
let getTxCacheSizeResponse: GetTxCacheSizeResponse;
getTxCacheSizeResponse = GetTxCacheSizeResponse.fromJSON(
await this.fetchData("/getTxCacheSize", {}),
);
if (getTxCacheSizeResponse.errorCode === 0) {
getTxCacheSizeResponse.errorCode = 0;
getTxCacheSizeResponse.errorDesc = "ok";
getTxCacheSizeResponse.result = GetTxCacheSizeResult.fromJSON(
await this.fetchData("/getTxCacheSize", {}),
);
getTxCacheSizeResponse.success = true;
}
return getTxCacheSizeResponse;
}
}