From 97ca722a9620e9c9c881750842aaebed09eb7260 Mon Sep 17 00:00:00 2001
From: Florent Poittevin <florent.poittevin@unige.ch>
Date: Tue, 7 Nov 2023 11:13:29 +0100
Subject: [PATCH] refactor(ssr): change sync methods into async

---
 .../lib/server/helpers/server-cache.helper.ts |  15 ++-
 .../src/lib/server/server.ts                  |  15 +--
 .../server/services/server-cache.service.ts   | 110 +++++++++++-------
 3 files changed, 84 insertions(+), 56 deletions(-)

diff --git a/projects/solidify-frontend/src/lib/server/helpers/server-cache.helper.ts b/projects/solidify-frontend/src/lib/server/helpers/server-cache.helper.ts
index 7ba07596a..67fde9d76 100644
--- a/projects/solidify-frontend/src/lib/server/helpers/server-cache.helper.ts
+++ b/projects/solidify-frontend/src/lib/server/helpers/server-cache.helper.ts
@@ -58,21 +58,20 @@ export class ServerCacheHelper {
     return cacheRequest as CacheRequestModel;
   }
 
-  static cleanCacheByResourceId(logger: Logger, serverEnvironment: DefaultSolidifyServerEnvironment, ssrCache: SsrCache, resource: string, id: string): Promise<boolean> {
+  static async cleanCacheByResourceId(logger: Logger, serverEnvironment: DefaultSolidifyServerEnvironment, ssrCache: SsrCache, resource: string, id: string): Promise<boolean> {
     const cacheName = ServerCacheHelper.generateCacheName(resource, id);
     if (ssrCache.has(cacheName)) {
-      return ssrCache.clearResource(cacheName).then(() => {
+      try {
+        await ssrCache.clearResource(cacheName);
         logger.info(`Cache SSR cleaned for resource '${resource}' and id '${id}'`);
         return true;
-      }).catch(err => {
+      } catch (err) {
         logger.error(`Unable to clean SSR cache for resource '${resource}' and id '${id}'. See error ${err}`);
         return false;
-      });
+      }
     }
-    return Promise.resolve(false).then(() => {
-      logger.error(`Unable to find SSR cache to clean for resource '${resource}' and id '${id}'`);
-      return false;
-    });
+    logger.error(`Unable to find SSR cache to clean for resource '${resource}' and id '${id}'`);
+    return false;
   };
 
   static generateCacheKey(cacheName: string, cacheVersion: string): string {
diff --git a/projects/solidify-frontend/src/lib/server/server.ts b/projects/solidify-frontend/src/lib/server/server.ts
index 4c77b641f..5e6a8e18e 100644
--- a/projects/solidify-frontend/src/lib/server/server.ts
+++ b/projects/solidify-frontend/src/lib/server/server.ts
@@ -165,7 +165,7 @@ export class SsrServer {
     server.use(this._nodeTools.express.json());
 
     if (isNonEmptyArray(this._serverEnvironment.staticRoutes)) {
-      server.get(this._serverEnvironment.staticRoutes, (req, res) => {
+      server.get(this._serverEnvironment.staticRoutes, async (req, res) => {
         this._logger.info("server.ts: serve static file : " + req.url);
         let url = req.url;
         const indexOfQueryParam = url.indexOf("?");
@@ -248,15 +248,16 @@ export class SsrServer {
       users: {[this._serverEnvironment.cleanCacheEndpointsBasicAuthLogin]: this._serverEnvironment.cleanCacheEndpointsBasicAuthPassword},
     }), router);
 
-    server.post(["/clean-ssr-cache/all"], (req, res) => {
-      this._ssrCache.clearAll().then(() => {
+    server.post(["/clean-ssr-cache/all"], async (req, res) => {
+      try {
+        await this._ssrCache.clearAll();
         res.status(200).send("Cache SSR cleaned");
-      }).catch(err => {
+      } catch (e) {
         res.status(400).send("Unable to clean SSR cache");
-      });
+      }
     });
 
-    server.post([`/clean-ssr-cache/:resource`], (req, res) => {
+    server.post([`/clean-ssr-cache/:resource`], async (req, res) => {
       const resource = req.params.resource;
       const listId = req.body as string[];
       if (isNullOrUndefinedOrEmptyArray(listId)) {
@@ -279,7 +280,7 @@ export class SsrServer {
         });
     });
 
-    server.post([`/clean-ssr-cache/:resource/:id`], (req, res) => {
+    server.post([`/clean-ssr-cache/:resource/:id`], async (req, res) => {
       const resource = req.params.resource;
       const id = req.params.id;
       ServerCacheHelper.cleanCacheByResourceId(this._logger, this._serverEnvironment, this._ssrCache, resource, id).then(result => {
diff --git a/projects/solidify-frontend/src/lib/server/services/server-cache.service.ts b/projects/solidify-frontend/src/lib/server/services/server-cache.service.ts
index af9788de0..c2db0a002 100644
--- a/projects/solidify-frontend/src/lib/server/services/server-cache.service.ts
+++ b/projects/solidify-frontend/src/lib/server/services/server-cache.service.ts
@@ -21,6 +21,7 @@
  * ----------------------------------------------------------------------------------------------%%
  */
 
+import {Stats} from "node:fs";
 import {Logger} from "winston";
 import {SOLIDIFY_CONSTANTS} from "../../core/constants";
 import {
@@ -64,20 +65,21 @@ export class SsrCache {
     return this._nodeTools.join(this._cacheLocation, ...relativePath);
   }
 
-  private _createDirectoryIfNotExist(...relativePath: string[]): void {
+  private async _createDirectoryIfNotExist(...relativePath: string[]): Promise<void> {
     const absolutePath = this._getAbsolutePath(...relativePath);
-    if (!this._nodeTools.fs.existsSync(absolutePath)) {
-      this._nodeTools.fs.mkdirSync(absolutePath, {recursive: true});
+    const exist = await this._fileExist(absolutePath);
+    if (!exist) {
+      await this._nodeTools.fsp.mkdir(absolutePath, {recursive: true});
     }
   }
 
-  private _deleteDirectoryIfExit(...relativePath: string[]): Promise<void> {
+  private async _deleteDirectoryIfExit(...relativePath: string[]): Promise<void> {
     const absolutePath = this._getAbsolutePath(...relativePath);
-    return this._deleteDirectoryIfExitAbsolute(absolutePath);
+    return await this._deleteDirectoryIfExitAbsolute(absolutePath);
   }
 
-  private _deleteDirectoryIfExitAbsolute(absolutePath: string): Promise<void> {
-    if (this._nodeTools.fs.existsSync(absolutePath)) {
+  private async _deleteDirectoryIfExitAbsolute(absolutePath: string): Promise<void> {
+    if (await this._fileExist(absolutePath)) {
       return this._deleteDirectoryAbsolute(absolutePath);
     }
     return Promise.resolve();
@@ -109,7 +111,7 @@ export class SsrCache {
    * @param cacheRequest
    * @param acceptGzip
    */
-  getPath(cacheRequest: CacheRequestModel, acceptGzip: boolean): string | undefined {
+  getPath(cacheRequest: CacheRequestModel, acceptGzip: boolean): Promise<string | undefined> {
     const cacheName = cacheRequest.cacheName;
     const md5Path = this._generateMd5RelativePath(cacheName).join(SOLIDIFY_CONSTANTS.SEPARATOR);
     const path = this._nodeTools.join(md5Path, cacheRequest.cacheKey + this._HTML_EXTENSION);
@@ -126,17 +128,21 @@ export class SsrCache {
     return undefined;
   }
 
-  private _getAbsolutePathCache(cacheRequest: CacheRequestModel, absolutePath: string, returnCompressed: boolean): string | undefined {
+  private async _getAbsolutePathCache(cacheRequest: CacheRequestModel, absolutePath: string, returnCompressed: boolean): Promise<string | undefined> {
     const absolutePathGzip = absolutePath + this._GZIP_EXTENSION;
     const absolutePathUsed = returnCompressed ? absolutePathGzip : absolutePath;
-    const isValidCache = this._isValidCache(cacheRequest.requestOption.cacheTimeToLiveInMinutes, absolutePathUsed);
-    if (isNullOrUndefined(isValidCache) || isTrue(isValidCache)) {
-      return absolutePathUsed;
+    try {
+      const isValidCache = await this._isValidCache(cacheRequest.requestOption.cacheTimeToLiveInMinutes, absolutePathUsed);
+      if (isNullOrUndefined(isValidCache) || isTrue(isValidCache)) {
+        return absolutePathUsed;
+      }
+      this._logger.info(`server-cache.service.ts: Remove expired cache for version ${cacheRequest.cacheKey}`);
+      await this._deleteDirectoryIfExitAbsolute(absolutePath);
+      await this._deleteDirectoryIfExitAbsolute(absolutePathGzip);
+      return undefined;
+    } catch (e) {
+      return undefined;
     }
-    this._logger.info(`server-cache.service.ts: Remove expired cache for version ${cacheRequest.cacheKey}`);
-    this._deleteDirectoryIfExitAbsolute(absolutePath);
-    this._deleteDirectoryIfExitAbsolute(absolutePathGzip);
-    return undefined;
   }
 
   /**
@@ -146,22 +152,22 @@ export class SsrCache {
    * @param value
    * @param ttl
    */
-  set(cacheRequest: CacheRequestModel, value: any): Promise<void> {
+  async set(cacheRequest: CacheRequestModel, value: any): Promise<void> {
     const cacheName = cacheRequest.cacheName;
     const md5RelativePath = this._generateMd5RelativePath(cacheName).join(SOLIDIFY_CONSTANTS.SEPARATOR);
-    this._createDirectoryIfNotExist(md5RelativePath);
+    await this._createDirectoryIfNotExist(md5RelativePath);
     const relativePath = this._nodeTools.join(md5RelativePath, cacheRequest.cacheKey + this._HTML_EXTENSION);
     const absolutePath = this._getAbsolutePath(relativePath);
-    this._deleteDirectoryIfExit(relativePath);
-    return this._nodeTools.fsp.appendFile(absolutePath, value, {encoding: this._HTML_ENCODING})
-      .then(() => {
-        this._nodeTools.fs.createReadStream(absolutePath)
-          .pipe(this._nodeTools.zlib.createGzip({level: 9}))
-          .pipe(this._nodeTools.fs.createWriteStream(`${absolutePath}${this._GZIP_EXTENSION}`))
-          .on("finish", () => this._logger.verbose(`server-cache.service.ts: Successfully generate gzip for cache result ${cacheRequest.cacheKey}`));
-      }).catch(e => {
-        this._logger.error(`server-cache.service.ts: Unable to generate gzip version for cache ${cacheRequest.cacheKey}`, e);
-      });
+    await this._deleteDirectoryIfExit(relativePath);
+    try {
+      await this._nodeTools.fsp.appendFile(absolutePath, value, {encoding: this._HTML_ENCODING});
+      this._nodeTools.fs.createReadStream(absolutePath)
+        .pipe(this._nodeTools.zlib.createGzip({level: 9}))
+        .pipe(this._nodeTools.fs.createWriteStream(`${absolutePath}${this._GZIP_EXTENSION}`))
+        .on("finish", () => this._logger.verbose(`server-cache.service.ts: Successfully generate gzip for cache result ${cacheRequest.cacheKey}`));
+    } catch (e) {
+      this._logger.error(`server-cache.service.ts: Unable to generate gzip version for cache ${cacheRequest.cacheKey}`, e);
+    }
   }
 
   /**
@@ -169,16 +175,16 @@ export class SsrCache {
    *
    * @param cacheName resource and eventually id (ex: home | archive-58eb331b-a45f-4848-8c3c-1e613730d213)
    */
-  clearResource(cacheName: string): Promise<any> {
+  async clearResource(cacheName: string): Promise<any> {
     const relativePath = this._generateMd5RelativePath(cacheName);
-    return this._deleteDirectoryIfExit(...relativePath);
+    return await this._deleteDirectoryIfExit(...relativePath);
   }
 
   /**
    * Clear all ssr cache
    */
-  clearAll(): Promise<void> {
-    return this._deleteDirectoryIfExit();
+  async clearAll(): Promise<void> {
+    return await this._deleteDirectoryIfExit();
   }
 
   private _generateMd5RelativePath(cacheName: string): string[] {
@@ -189,22 +195,44 @@ export class SsrCache {
     return this._nodeTools.md5(cacheName);
   }
 
-  private _isValidCache(timeToLiveInMinutes: number | undefined, absolutePath: string): boolean | undefined {
+  private async _isValidCache(timeToLiveInMinutes: number | undefined, absolutePath: string): Promise<boolean | undefined> {
     if (isNullOrUndefined(timeToLiveInMinutes)) {
       return undefined;
     }
-    const creationDate = this._getFileCreationDate(absolutePath);
-    if (isNullOrUndefined(creationDate)) {
+    try {
+      const creationDate = await this._getFileCreationDate(absolutePath);
+      if (isNullOrUndefined(creationDate)) {
+        return undefined;
+      }
+      const currentDate = new Date();
+      const dateExpiration = new Date(creationDate.setMinutes(creationDate.getMinutes() + timeToLiveInMinutes));
+      const isValidCache = currentDate <= dateExpiration;
+      return isValidCache;
+    } catch (e) {
+      return undefined;
+    }
+  }
+
+  private async _getFileCreationDate(absolutePath: string): Promise<Date | undefined> {
+    try {
+      const stats = await this._fileStats(absolutePath);
+      return stats.birthtime;
+    } catch (e) {
       return undefined;
     }
-    const currentDate = new Date();
-    const dateExpiration = new Date(creationDate.setMinutes(creationDate.getMinutes() + timeToLiveInMinutes));
-    const isValidCache = currentDate <= dateExpiration;
-    return isValidCache;
   }
 
-  private _getFileCreationDate(absolutePath: string): Date | undefined {
-    return this._nodeTools.fs.statSync(absolutePath)?.birthtime;
+  private async _fileExist(absoluteFilePath: string): Promise<boolean> {
+    try {
+      await this._fileStats(absoluteFilePath);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+
+  private async _fileStats(absoluteFilePath: string): Promise<Stats> {
+    return await this._nodeTools.fsp.stat(absoluteFilePath);
   }
 }
 
-- 
GitLab