1 | import { Request as ERequest, Response as EResponse } from "express";
|
2 | import AsyncResponse from "./async.response";
|
3 | import * as Jimp from "jimp";
|
4 | import * as fs from "fs";
|
5 | import { app } from "./app";
|
6 |
|
7 | function fileExsist(path: string): Promise<boolean> {
|
8 | return new Promise<boolean>((res, _) => {
|
9 | fs.exists(path, val => {
|
10 | res(val);
|
11 | });
|
12 | });
|
13 | }
|
14 |
|
15 | function saveToCache(path: string, s: Jimp) {
|
16 | if (!app.config.chachingImages) {
|
17 | return;
|
18 | }
|
19 | s.writeAsync(path).catch(err => console.error(err));
|
20 | }
|
21 |
|
22 | /**
|
23 | * This interface defines the currently available options for files.
|
24 | */
|
25 | export interface FileOptions {
|
26 | width: number;
|
27 | height?: number;
|
28 | }
|
29 | /**
|
30 | * Generation of a File response.
|
31 | */
|
32 | export default class FileResponse extends AsyncResponse {
|
33 | private readonly path: string;
|
34 | private _contentType?: string;
|
35 | private _fileName: string;
|
36 | private _options?: FileOptions;
|
37 | constructor(path: string) {
|
38 | super();
|
39 | this.path = path;
|
40 | }
|
41 |
|
42 | /**
|
43 | * Set the content type of the response.
|
44 | * @param value the content type
|
45 | */
|
46 | set contentType(value: string) {
|
47 | this._contentType = value;
|
48 | }
|
49 |
|
50 | /**
|
51 | * Set the name of the file to download
|
52 | * @param value the name of the file
|
53 | */
|
54 | set fileName(value: string) {
|
55 | this._fileName = value;
|
56 | }
|
57 |
|
58 | /**
|
59 | * Set the file options, to correctly generate the response.
|
60 | * @param value the FileOptions
|
61 | */
|
62 | set options(value: FileOptions) {
|
63 | this._options = value;
|
64 | }
|
65 |
|
66 | private download(res: EResponse, path: string) {
|
67 | if (this._fileName) {
|
68 | return res.download(path, this._fileName);
|
69 | }
|
70 | res.download(path);
|
71 | }
|
72 | /**
|
73 | * Generation of the response.
|
74 | * This method can eventually perform some transformation on output if a
|
75 | * FileOptions was specified.
|
76 | */
|
77 | async asyncResponse(_: ERequest, res: EResponse): Promise<void> {
|
78 | if (this._contentType) {
|
79 | res.contentType(this._contentType);
|
80 | }
|
81 | let path = await app.config.ufs.getToCache(
|
82 | this.path,
|
83 | app.config.cachePath
|
84 | );
|
85 |
|
86 | if (!this._options) {
|
87 | return this.download(res, path);
|
88 | }
|
89 |
|
90 | let cachePath = path + "_" + JSON.stringify(this._options);
|
91 | if (await fileExsist(cachePath)) {
|
92 | return this.download(res, cachePath);
|
93 | }
|
94 |
|
95 | let img = {} as Jimp;
|
96 | let hasProcessing = false;
|
97 | if (!this._options.height) {
|
98 | img = await Jimp.read(path);
|
99 | img = img.resize(this._options.width, Jimp.AUTO);
|
100 | hasProcessing = true;
|
101 | }
|
102 | if (this._options.width && this._options.height) {
|
103 | hasProcessing = true;
|
104 | img = await Jimp.read(path);
|
105 | img = img.resize(this._options.width, this._options.height);
|
106 |
|
107 | }
|
108 | if (hasProcessing) {
|
109 | let buff = await (img as Jimp).getBufferAsync(this._contentType as string);
|
110 | res.send(buff);
|
111 | res.end();
|
112 | saveToCache(cachePath, img);
|
113 | return;
|
114 | }
|
115 | this.download(res, path);
|
116 | }
|
117 | }
|
118 |
|
\ | No newline at end of file |