Răsfoiți Sursa

refactor(asset-server-plugin): Change the way files are served

This change makes it possible to serve files from any source (not just local file system) so that any valid AssetStorageStrategy should be compatible with the plugin.
Michael Bromley 5 ani în urmă
părinte
comite
f75fbed783

+ 1 - 0
packages/asset-server-plugin/package.json

@@ -30,6 +30,7 @@
     "typescript": "3.8.3"
   },
   "dependencies": {
+    "file-type": "^14.3.0",
     "fs-extra": "^9.0.0",
     "sharp": "0.25.2"
   }

+ 42 - 14
packages/asset-server-plugin/src/plugin.ts

@@ -13,6 +13,7 @@ import {
 } from '@vendure/core';
 import { createHash } from 'crypto';
 import express, { NextFunction, Request, Response } from 'express';
+import { fromBuffer } from 'file-type';
 import fs from 'fs-extra';
 import { Server } from 'http';
 import path from 'path';
@@ -188,10 +189,6 @@ export class AssetServerPlugin implements OnVendureBootstrap, OnVendureClose {
         fs.ensureDirSync(cachePath);
         this.createAssetServer();
         const { hostname, port } = AssetServerPlugin.options;
-        // console.log('SWAGGGGGGGG!');
-        // this.healthCheckRegistryService.registerIndicatorFunction(() =>
-        //     this.dns.pingCheck('asset-server', `${hostname}:${port}`),
-        // );
     }
 
     /** @internal */
@@ -209,7 +206,7 @@ export class AssetServerPlugin implements OnVendureBootstrap, OnVendureClose {
         assetServer.get('/health', (req, res) => {
             res.send('ok');
         });
-        assetServer.use(this.serveStaticFile(), this.generateTransformedImage());
+        assetServer.use(this.sendAsset(), this.generateTransformedImage());
 
         this.server = assetServer.listen(AssetServerPlugin.options.port, () => {
             const addressInfo = this.server.address();
@@ -224,15 +221,24 @@ export class AssetServerPlugin implements OnVendureBootstrap, OnVendureClose {
     }
 
     /**
-     * Sends the file requested to the broswer.
+     * Reads the file requested and send the response to the browser.
      */
-    private serveStaticFile() {
-        return (req: Request, res: Response) => {
-            const filePath = path.join(
-                AssetServerPlugin.options.assetUploadDir,
-                this.getFileNameFromRequest(req),
-            );
-            res.sendFile(filePath);
+    private sendAsset() {
+        return async (req: Request, res: Response, next: NextFunction) => {
+            const key = this.getFileNameFromRequest(req);
+            try {
+                const file = await AssetServerPlugin.assetStorage.readFileToBuffer(key);
+                let mimeType = this.getMimeType(key);
+                if (!mimeType) {
+                    mimeType = (await fromBuffer(file))?.mime || 'application/octet-stream';
+                }
+                res.contentType(mimeType);
+                res.send(file);
+            } catch (e) {
+                const err = new Error('File not found');
+                (err as any).status = 404;
+                return next(err);
+            }
         };
     }
 
@@ -243,7 +249,7 @@ export class AssetServerPlugin implements OnVendureBootstrap, OnVendureClose {
      */
     private generateTransformedImage() {
         return async (err: any, req: Request, res: Response, next: NextFunction) => {
-            if (err && err.status === 404) {
+            if (err && (err.status === 404 || err.statusCode === 404)) {
                 if (req.query) {
                     Logger.debug(`Pre-cached Asset not found: ${req.path}`, loggerCtx);
                     let file: Buffer;
@@ -309,4 +315,26 @@ export class AssetServerPlugin implements OnVendureBootstrap, OnVendureClose {
         const dirName = path.dirname(fileName);
         return path.join(dirName, `${baseName}${suffix}${ext}`);
     }
+
+    /**
+     * Attempt to get the mime type from the file name.
+     */
+    private getMimeType(fileName: string): string | undefined {
+        const ext = path.extname(fileName);
+        switch (ext) {
+            case 'jpg':
+            case 'jpeg':
+                return 'image/jpeg';
+            case 'png':
+                return 'image/png';
+            case 'gif':
+                return 'image/gif';
+            case 'svg':
+                return 'image/svg+xml';
+            case 'tiff':
+                return 'image/tiff';
+            case 'webp':
+                return 'image/webp';
+        }
+    }
 }