-
Notifications
You must be signed in to change notification settings - Fork 59
/
Middleware.ts
141 lines (132 loc) · 5.2 KB
/
Middleware.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// eslint-disable-next-line max-classes-per-file
import BigNumber from 'bignumber.js';
import { OperationArguments, OperationSpec } from '@azure/core-client';
import {
genRequestQueuesPolicy, genCombineGetRequestsPolicy, genErrorFormatterPolicy,
genVersionCheckPolicy, genRetryOnFailurePolicy,
} from './utils/autorest';
import { Middleware as MiddlewareApi, MiddlewareOptionalParams, ErrorResponse } from './apis/middleware';
import { mapObject } from './utils/other';
import { Encoded } from './utils/encoder';
import { ConsensusProtocolVersion } from './tx/builder/constants';
const bigIntPropertyNames = [] as const;
const numberPropertyNames = [] as const;
class MiddlewareTransformed extends MiddlewareApi {
override async sendOperationRequest(
operationArguments: OperationArguments,
operationSpec: OperationSpec,
): Promise<any> {
const args = mapObject(
operationArguments,
([key, value]) => [key, this.#encodeArg(value)],
) as OperationArguments;
return this.#decodeRes(await super.sendOperationRequest(args, operationSpec));
}
#mapData(data: any, transform: {
bigInt: (v: any) => any;
number: (v: any) => any;
}): unknown {
if (Array.isArray(data)) return data.map((d) => this.#mapData(d, transform));
if (data != null && typeof data === 'object') {
return mapObject(data, ([key, value]) => {
if (value == null) return [key, value];
if (bigIntPropertyNames.some((k) => k === key)) return [key, transform.bigInt(value)];
if (numberPropertyNames.some((k) => k === key)) return [key, transform.number(value)];
return [key, this.#mapData(value, transform)];
});
}
return data;
}
#encodeArg(data: any): any {
return this.#mapData(data, {
bigInt: (value) => {
if (value instanceof BigNumber) return value.toFixed();
return value.toString();
},
number: (value) => value.toString(),
});
}
#decodeRes(data: any): any {
return this.#mapData(data, {
bigInt: (value) => BigInt(value),
number: (value) => +value,
});
}
}
type BigIntPropertyNames = typeof bigIntPropertyNames[number];
type NumberPropertyNames = typeof numberPropertyNames[number];
type PreserveOptional<NewType, OrigType> =
OrigType extends undefined ? NewType | undefined : NewType;
export type TransformMiddlewareType<Type> =
Type extends (...args: infer Args) => infer Ret
? (...args: TransformMiddlewareType<Args>) => TransformMiddlewareType<Ret>
: Type extends [infer Item, ...infer Rest]
? [TransformMiddlewareType<Item>, ...TransformMiddlewareType<Rest>]
: Type extends Array<infer Item>
? Array<TransformMiddlewareType<Item>>
: Type extends Promise<infer T>
? Promise<TransformMiddlewareType<T>>
: Type extends { [P in any]: any }
? {
[Property in keyof Type]:
Property extends BigIntPropertyNames
? PreserveOptional<bigint, Type[Property]>
: Property extends NumberPropertyNames
? PreserveOptional<number, Type[Property]>
: Property extends 'txHash'
? PreserveOptional<Encoded.TxHash, Type[Property]>
: Property extends 'bytecode'
? PreserveOptional<Encoded.ContractBytearray, Type[Property]>
: TransformMiddlewareType<Type[Property]>
}
: Type;
type MiddlewareTransformedApi = new (...args: ConstructorParameters<typeof MiddlewareApi>) => {
[Name in keyof InstanceType<typeof MiddlewareApi>]:
Name extends 'pipeline' | 'sendRequest' | 'sendOperationRequest'
? MiddlewareApi[Name] : TransformMiddlewareType<MiddlewareApi[Name]>
};
export interface MiddlewareInfo {
url: string;
nodeNetworkId: string;
version: string;
consensusProtocolVersion: ConsensusProtocolVersion;
}
export default class Middleware
extends (MiddlewareTransformed as unknown as MiddlewareTransformedApi) {
/**
* @param url - Url for middleware API
* @param options - Options
* @param options.ignoreVersion - Don't ensure that the middleware is supported
* @param options.retryCount - Amount of extra requests to do in case of failure
* @param options.retryOverallDelay - Time in ms to wait between all retries
*/
constructor(
url: string,
{
ignoreVersion = false, retryCount = 3, retryOverallDelay = 800, ...options
}: MiddlewareOptionalParams & {
ignoreVersion?: boolean;
retryCount?: number;
retryOverallDelay?: number;
} = {},
) {
// eslint-disable-next-line constructor-super
super(url, {
allowInsecureConnection: true,
additionalPolicies: [
genRequestQueuesPolicy(),
genCombineGetRequestsPolicy(),
genRetryOnFailurePolicy(retryCount, retryOverallDelay),
genErrorFormatterPolicy((body: ErrorResponse) => ` ${body.error}`),
],
...options,
});
if (!ignoreVersion) {
const statusPromise = this.getStatus();
const versionPromise = statusPromise.then(({ mdwVersion }) => mdwVersion, (error) => error);
this.pipeline.addPolicy(
genVersionCheckPolicy('middleware', '/v2/status', versionPromise, '1.47.0', '2.0.0'),
);
}
}
}