build: switch to NodeNext module resolution
[e-mobility-charging-stations-simulator.git] / src / performance / storage / JsonFileStorage.ts
1 // Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
2
3 import { closeSync, existsSync, mkdirSync, openSync, writeSync } from 'node:fs';
4 import { dirname } from 'node:path';
5
6 import { Storage } from './Storage.js';
7 import { BaseError } from '../../exception/index.js';
8 import { FileType, type Statistics } from '../../types/index.js';
9 import {
10 AsyncLock,
11 AsyncLockType,
12 JSONStringifyWithMapSupport,
13 handleFileException,
14 isNullOrUndefined,
15 } from '../../utils/index.js';
16
17 export class JsonFileStorage extends Storage {
18 private static performanceRecords: Map<string, Statistics>;
19
20 private fd?: number;
21
22 constructor(storageUri: string, logPrefix: string) {
23 super(storageUri, logPrefix);
24 this.dbName = this.storageUri.pathname;
25 }
26
27 public storePerformanceStatistics(performanceStatistics: Statistics): void {
28 this.checkPerformanceRecordsFile();
29 JsonFileStorage.performanceRecords.set(performanceStatistics.id, performanceStatistics);
30 AsyncLock.runExclusive(AsyncLockType.performance, () => {
31 writeSync(
32 this.fd!,
33 JSONStringifyWithMapSupport([...JsonFileStorage.performanceRecords.values()], 2),
34 0,
35 'utf8',
36 );
37 }).catch((error) => {
38 handleFileException(
39 this.dbName,
40 FileType.PerformanceRecords,
41 error as NodeJS.ErrnoException,
42 this.logPrefix,
43 );
44 });
45 }
46
47 public open(): void {
48 JsonFileStorage.performanceRecords = new Map<string, Statistics>();
49 try {
50 if (isNullOrUndefined(this?.fd)) {
51 if (!existsSync(dirname(this.dbName))) {
52 mkdirSync(dirname(this.dbName), { recursive: true });
53 }
54 this.fd = openSync(this.dbName, 'w');
55 }
56 } catch (error) {
57 handleFileException(
58 this.dbName,
59 FileType.PerformanceRecords,
60 error as NodeJS.ErrnoException,
61 this.logPrefix,
62 );
63 }
64 }
65
66 public close(): void {
67 JsonFileStorage.performanceRecords.clear();
68 try {
69 if (this?.fd) {
70 closeSync(this.fd);
71 delete this?.fd;
72 }
73 } catch (error) {
74 handleFileException(
75 this.dbName,
76 FileType.PerformanceRecords,
77 error as NodeJS.ErrnoException,
78 this.logPrefix,
79 );
80 }
81 }
82
83 private checkPerformanceRecordsFile(): void {
84 if (!this?.fd) {
85 throw new BaseError(
86 `${this.logPrefix} Performance records '${this.dbName}' file descriptor not found`,
87 );
88 }
89 }
90 }