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
, milliSeconds
));
20 public static secondsToHHMMSS(seconds
: number): string {
21 return Utils
.milliSecondsToHHMMSS(seconds
* 1000);
24 public static milliSecondsToHHMMSS(milliSeconds
: number): string {
25 return new Date(milliSeconds
).toISOString().substr(11, 8);
28 public static removeExtraEmptyLines(tab
: string[]): void {
30 for (let i
= tab
.length
- 1; i
> 0; i
--) {
31 // Two consecutive empty lines?
32 if (tab
[i
].length
=== 0 && tab
[i
- 1].length
=== 0) {
33 // Remove the last one
37 if (i
=== 1 && tab
[i
- 1].length
=== 0) {
38 // Remove the first one
44 public static convertToDate(value
: unknown
): Date {
50 if (!(value
instanceof Date)) {
51 return new Date(value
as string);
56 public static convertToInt(value
: unknown
): number {
57 let changedValue
: number = value
as number;
61 if (Number.isSafeInteger(value
)) {
62 return value
as number;
65 if (Utils
.isString(value
)) {
67 changedValue
= parseInt(value
as string);
72 public static convertToFloat(value
: unknown
): number {
73 let changedValue
: number = value
as number;
78 if (Utils
.isString(value
)) {
80 changedValue
= parseFloat(value
as string);
85 public static convertToBoolean(value
: unknown
): boolean {
90 if (typeof value
=== 'boolean') {
95 result
= (value
=== 'true');
101 public static getRandomFloat(max
: number, min
= 0): number {
102 return (crypto
.randomBytes(4).readUInt32LE() / 0xffffffff) * (max
- min
) + min
;
105 public static getRandomInt(max
: number, min
= 0): number {
107 return Math.floor(Utils
.secureRandom() * (max
- min
+ 1)) + min
;
109 return Math.floor(Utils
.secureRandom() * (max
+ 1));
112 public static roundTo(numberValue
: number, scale
: number): number {
113 const roundPower
= Math.pow(10, scale
);
114 return Math.round(numberValue
* roundPower
) / roundPower
;
117 public static truncTo(numberValue
: number, scale
: number): number {
118 const truncPower
= Math.pow(10, scale
);
119 return Math.trunc(numberValue
* truncPower
) / truncPower
;
122 public static getRandomFloatRounded(max
: number, min
= 0, scale
= 2): number {
124 return Utils
.roundTo(Utils
.getRandomFloat(max
, min
), scale
);
126 return Utils
.roundTo(Utils
.getRandomFloat(max
), scale
);
129 public static getRandomFloatFluctuatedRounded(staticValue
: number, fluctuationPercent
: number, scale
= 2): number {
130 if (fluctuationPercent
=== 0) {
131 return Utils
.roundTo(staticValue
, scale
);
133 const fluctuationRatio
= fluctuationPercent
/ 100;
134 return Utils
.getRandomFloatRounded(staticValue
* (1 + fluctuationRatio
), staticValue
* (1 - fluctuationRatio
), scale
);
137 public static cloneObject
<T
>(object
: T
): T
{
138 return JSON
.parse(JSON
.stringify(object
)) as T
;
141 public static isIterable
<T
>(obj
: T
): boolean {
143 return typeof obj
[Symbol
.iterator
] === 'function';
148 public static isEmptyJSon(document
: unknown
): boolean {
154 if (typeof document
!== 'object') {
158 return Object.keys(document
).length
=== 0;
161 public static isString(value
: unknown
): boolean {
162 return typeof value
=== 'string';
165 public static isUndefined(value
: unknown
): boolean {
166 return typeof value
=== 'undefined';
169 public static isNullOrUndefined(value
: unknown
): boolean {
170 // eslint-disable-next-line no-eq-null, eqeqeq
177 public static isEmptyArray(object
: unknown
): boolean {
181 if (Array.isArray(object
) && object
.length
> 0) {
187 public static isEmptyObject(obj
: Record
<string, unknown
>): boolean {
188 return !Object.keys(obj
).length
;
191 public static insertAt
= (str
: string, subStr
: string, pos
: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
194 * @param [retryNumber=0]
195 * @returns delay in milliseconds
197 public static exponentialDelay(retryNumber
= 0): number {
198 const delay
= Math.pow(2, retryNumber
) * 100;
199 const randomSum
= delay
* 0.2 * Utils
.secureRandom(); // 0-20% of the delay
200 return delay
+ randomSum
;
204 * Convert websocket error code to human readable string message
206 * @param code websocket error code
207 * @returns human readable string message
209 public static getWebSocketCloseEventStatusString(code
: number): string {
210 if (code
>= 0 && code
<= 999) {
212 } else if (code
>= 1016) {
214 return '(For WebSocket standard)';
215 } else if (code
<= 2999) {
216 return '(For WebSocket extensions)';
217 } else if (code
<= 3999) {
218 return '(For libraries and frameworks)';
219 } else if (code
<= 4999) {
220 return '(For applications)';
223 if (!Utils
.isUndefined(WebSocketCloseEventStatusString
[code
])) {
224 return WebSocketCloseEventStatusString
[code
] as string;
229 public static workerPoolInUse(): boolean {
230 return [WorkerProcessType
.DYNAMIC_POOL
, WorkerProcessType
.STATIC_POOL
].includes(Configuration
.getWorkerProcess());
233 public static workerDynamicPoolInUse(): boolean {
234 return Configuration
.getWorkerProcess() === WorkerProcessType
.DYNAMIC_POOL
;
238 * Generate a cryptographically secure random number in the [0,1[ range
242 public static secureRandom(): number {
243 return crypto
.randomBytes(4).readUInt32LE() / 0x100000000;