1 import Configuration from
'./Configuration';
2 import { WebSocketCloseEventStatusString
} from
'../types/WebSocket';
3 import { WorkerProcessType
} from
'../types/Worker';
4 import crypto from
'crypto';
5 import { v4
as uuid
} from
'uuid';
7 export default class Utils
{
8 public static logPrefix(prefixString
= ''): string {
9 return new Date().toLocaleString() + prefixString
;
12 public static generateUUID(): string {
16 public static async sleep(milliSeconds
: number): Promise
<NodeJS
.Timeout
> {
17 return new Promise((resolve
) => setTimeout(resolve
as () => void, milliSeconds
));
20 public static formatDurationMilliSeconds(duration
: number): string {
21 duration
= Utils
.convertToInt(duration
);
22 const hours
= Math.floor(duration
/ (3600 * 1000));
23 const minutes
= Math.floor((duration
/ 1000 - (hours
* 3600)) / 60);
24 const seconds
= duration
/ 1000 - (hours
* 3600) - (minutes
* 60);
25 let hoursStr
= hours
.toString();
26 let minutesStr
= minutes
.toString();
27 let secondsStr
= seconds
.toString();
30 hoursStr
= '0' + hours
.toString();
33 minutesStr
= '0' + minutes
.toString();
36 secondsStr
= '0' + seconds
.toString();
38 return hoursStr
+ ':' + minutesStr
+ ':' + secondsStr
.substring(0, 6);
41 public static formatDurationSeconds(duration
: number): string {
42 return Utils
.formatDurationMilliSeconds(duration
* 1000);
45 public static convertToDate(value
: unknown
): Date {
51 if (!(value
instanceof Date)) {
52 return new Date(value
as string);
57 public static convertToInt(value
: unknown
): number {
58 let changedValue
: number = value
as number;
62 if (Number.isSafeInteger(value
)) {
63 return value
as number;
66 if (Utils
.isString(value
)) {
68 changedValue
= parseInt(value
as string);
73 public static convertToFloat(value
: unknown
): number {
74 let changedValue
: number = value
as number;
79 if (Utils
.isString(value
)) {
81 changedValue
= parseFloat(value
as string);
86 public static convertToBoolean(value
: unknown
): boolean {
91 if (typeof value
=== 'boolean') {
96 result
= (value
=== 'true');
102 public static getRandomFloat(max
: number, min
= 0, negative
= false): number {
103 if (max
< min
|| min
< 0 || max
< 0) {
104 throw new RangeError('Invalid interval');
106 const randomPositiveFloat
= crypto
.randomBytes(4).readUInt32LE() / 0xffffffff;
107 const sign
= (negative
&& randomPositiveFloat
< 0.5) ? -1 : 1;
108 return sign
* (randomPositiveFloat
* (max
- min
) + min
);
111 public static getRandomInteger(max
: number, min
= 0): number {
113 throw new RangeError('Invalid interval');
115 max
= Math.floor(max
);
117 if (max
< min
|| min
< 0) {
118 throw new RangeError('Invalid interval');
120 min
= Math.ceil(min
);
121 return Math.floor(Utils
.secureRandom() * (max
- min
+ 1)) + min
;
123 return Math.floor(Utils
.secureRandom() * (max
+ 1));
126 public static roundTo(numberValue
: number, scale
: number): number {
127 const roundPower
= Math.pow(10, scale
);
128 return Math.round(numberValue
* roundPower
) / roundPower
;
131 public static truncTo(numberValue
: number, scale
: number): number {
132 const truncPower
= Math.pow(10, scale
);
133 return Math.trunc(numberValue
* truncPower
) / truncPower
;
136 public static getRandomFloatRounded(max
: number, min
= 0, scale
= 2): number {
138 return Utils
.roundTo(Utils
.getRandomFloat(max
, min
), scale
);
140 return Utils
.roundTo(Utils
.getRandomFloat(max
), scale
);
143 public static getRandomFloatFluctuatedRounded(staticValue
: number, fluctuationPercent
: number, scale
= 2): number {
144 if (fluctuationPercent
=== 0) {
145 return Utils
.roundTo(staticValue
, scale
);
147 const fluctuationRatio
= fluctuationPercent
/ 100;
148 return Utils
.getRandomFloatRounded(staticValue
* (1 + fluctuationRatio
), staticValue
* (1 - fluctuationRatio
), scale
);
151 public static cloneObject
<T
>(object
: T
): T
{
152 return JSON
.parse(JSON
.stringify(object
)) as T
;
155 public static isIterable
<T
>(obj
: T
): boolean {
157 return typeof obj
[Symbol
.iterator
] === 'function';
162 public static isString(value
: unknown
): boolean {
163 return typeof value
=== 'string';
166 public static isUndefined(value
: unknown
): boolean {
167 return typeof value
=== 'undefined';
170 public static isNullOrUndefined(value
: unknown
): boolean {
171 // eslint-disable-next-line no-eq-null, eqeqeq
178 public static isEmptyArray(object
: unknown
): boolean {
182 if (Array.isArray(object
) && object
.length
> 0) {
188 public static isEmptyObject(obj
: Record
<string, unknown
>): boolean {
189 return !Object.keys(obj
).length
;
192 public static insertAt
= (str
: string, subStr
: string, pos
: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
195 * @param [retryNumber=0]
196 * @returns delay in milliseconds
198 public static exponentialDelay(retryNumber
= 0): number {
199 const delay
= Math.pow(2, retryNumber
) * 100;
200 const randomSum
= delay
* 0.2 * Utils
.secureRandom(); // 0-20% of the delay
201 return delay
+ randomSum
;
205 * Convert websocket error code to human readable string message
207 * @param code websocket error code
208 * @returns human readable string message
210 public static getWebSocketCloseEventStatusString(code
: number): string {
211 if (code
>= 0 && code
<= 999) {
213 } else if (code
>= 1016) {
215 return '(For WebSocket standard)';
216 } else if (code
<= 2999) {
217 return '(For WebSocket extensions)';
218 } else if (code
<= 3999) {
219 return '(For libraries and frameworks)';
220 } else if (code
<= 4999) {
221 return '(For applications)';
224 if (!Utils
.isUndefined(WebSocketCloseEventStatusString
[code
])) {
225 return WebSocketCloseEventStatusString
[code
] as string;
230 public static workerPoolInUse(): boolean {
231 return [WorkerProcessType
.DYNAMIC_POOL
, WorkerProcessType
.STATIC_POOL
].includes(Configuration
.getWorkerProcess());
234 public static workerDynamicPoolInUse(): boolean {
235 return Configuration
.getWorkerProcess() === WorkerProcessType
.DYNAMIC_POOL
;
238 public static async promiseWithTimeout
<T
>(
242 timeoutCallback
: () => void = () => { /* This is intentional */ }
244 // Create a timeout promise that rejects in timeout milliseconds
245 const timeoutPromise
= new Promise
<never>((_
, reject
) => {
248 reject(timeoutError
);
252 // Returns a race between timeout promise and the passed promise
253 return Promise
.race
<T
>([promise
, timeoutPromise
]);
257 * Generate a cryptographically secure random number in the [0,1[ range
261 public static secureRandom(): number {
262 return crypto
.randomBytes(4).readUInt32LE() / 0x100000000;