const express = require("express");
|
const router = express.Router();
|
const Promise = require("bluebird");
|
const fs = Promise.promisifyAll(require("fs"));
|
const manufacturerMainFolderPath = Config.furnview.furnplan_dev.bin + "\\..\\..\\..";
|
const etag = require("etag");
|
const fresh = require("fresh");
|
const zlib = require("zlib");
|
|
const manufacturerHashMap = new Map();
|
const programHashMap = new Map();
|
|
/**
|
* Converts any number to unsigned integer
|
*
|
* @param {number} number
|
*
|
* @returns number
|
*/
|
function toUnsignedInteger(number) {
|
return number >>> 0;
|
}
|
|
/**
|
* Creates a hash from a string via custom dh software algorithm
|
*
|
* @param {string} toHash
|
*
|
* @returns {string}
|
*/
|
function toDhHash(toHash) {
|
let hash = 0;
|
const pufferStr = toHash.toLowerCase();
|
|
for (let i = 0; i < pufferStr.length; i++) {
|
const character = pufferStr[i];
|
hash = toUnsignedInteger(
|
toUnsignedInteger(character.charCodeAt(0))
|
+ toUnsignedInteger(toUnsignedInteger(hash) << toUnsignedInteger(6))
|
+ toUnsignedInteger(toUnsignedInteger(hash) << toUnsignedInteger(16))
|
- toUnsignedInteger(hash)
|
);
|
}
|
|
return hash.toString(16);
|
}
|
|
/**
|
* Uses a wildcard algorithm to find fitting images
|
*
|
* @param {string} path
|
* @param {string} filename
|
*
|
* @returns {Promise.<*>}
|
*/
|
async function getFittingFilenameByWildcard(path, filename) {
|
const contents = await fs.readdirAsync(path);
|
|
try {
|
for (let i = 0; i < contents.length; i++) {
|
const item = contents[i];
|
|
const standardizedName = (item.replace(/^([0-9]{1,7})_.*/, "$1") + "0000000").substr(0, 7);
|
|
if (standardizedName === filename) {
|
return Promise.join(fs.statAsync(path + item), path + item);
|
}
|
}
|
|
return Promise.reject();
|
}
|
catch (e) {
|
return Promise.reject(e);
|
}
|
}
|
|
fs.readdirSync(manufacturerMainFolderPath).forEach((manufacturerFolderName) => {
|
const manufacturerFolderPath = manufacturerMainFolderPath + "\\" + manufacturerFolderName;
|
|
if (!fs.existsSync(manufacturerFolderPath) || !fs.statSync(manufacturerFolderPath).isDirectory()) return;
|
|
manufacturerHashMap.set(toDhHash(manufacturerFolderName), manufacturerFolderName);
|
|
fs.readdirSync(manufacturerFolderPath).forEach((programFolderName) => {
|
programHashMap.set(toDhHash(programFolderName), programFolderName);
|
});
|
});
|
|
router.get("/progimg/:manufacturer", (req, res) => {
|
const resList = [];
|
const manuFolder = manufacturerMainFolderPath + "\\" + req.params.manufacturer + "\\";
|
fs.readdirSync(manuFolder).forEach(function (itemFolder) {
|
if (fs.statSync(manuFolder + "\\" + itemFolder).isDirectory()) {
|
const photoFolder = manuFolder + "\\" + itemFolder + "\\" + "photos";
|
if (fs.existsSync(photoFolder)) {
|
fs.readdirSync(photoFolder).forEach(function (itemFile) {
|
const res = {};
|
res.prog = itemFolder;
|
res.file = itemFile;
|
resList.push(res);
|
});
|
}
|
}
|
});
|
return res.json(resList);
|
});
|
|
router.get("/:manufacturerHash/:programHash/:type/:name([%+*A-Za-z0-9/._-]+)$", (req, res) => {
|
let filename;
|
let filenameWithoutExtension;
|
let folderPath = "";
|
let fullPath;
|
|
if (req.params.manufacturerHash) {
|
if (manufacturerHashMap.get(req.params.manufacturerHash)) {
|
folderPath += manufacturerHashMap.get(req.params.manufacturerHash) + "\\";
|
}
|
else if (!(/[\\\/]/g.test(req.params.manufacturerHash))) {
|
folderPath += req.params.manufacturerHash + "\\";
|
}
|
}
|
if (req.params.programHash) {
|
if (req.params.programHash !== "-") {
|
if (programHashMap.get(req.params.programHash)) {
|
folderPath += programHashMap.get(req.params.programHash) + "\\";
|
}
|
else if (!(/[\\\/]/g.test(req.params.programHash))) {
|
folderPath += req.params.programHash + "\\";
|
}
|
}
|
else {
|
folderPath += "_global" + "\\";
|
}
|
}
|
if (req.params.type) {
|
if (req.params.type === "aus") {
|
folderPath += "ausf-images" + "\\";
|
}
|
if (req.params.type === "groups") {
|
folderPath += "ausf-images\\groups" + "\\";
|
}
|
if (req.params.type === "tex") {
|
folderPath += "textures" + "\\";
|
}
|
if (req.params.type === "texPath") {
|
folderPath = "";
|
}
|
if (req.params.type === "art") {
|
folderPath += "html\\kata-images" + "\\";
|
}
|
if (req.params.type === "ptImg") {
|
folderPath += "html" + "\\";
|
}
|
if (req.params.type === "logo") {
|
folderPath += "images\\" + manufacturerHashMap.get(req.params.manufacturerHash);
|
}
|
if (req.params.type === "logo_custom") {
|
folderPath += "images" + "\\";
|
}
|
if (req.params.type === "fp_ui") {
|
folderPath += "html\\h\\ci\\fp" + "\\";
|
}
|
if (req.params.type === "wall_img") {
|
folderPath += "html\\h\\wall\\images" + "\\";
|
}
|
}
|
if (req.params.name) {
|
filename = req.params.name;
|
filenameWithoutExtension = req.params.name.replace(/\..{3,4}$/ig, "");
|
}
|
|
fullPath = manufacturerMainFolderPath + "\\" + folderPath;
|
|
Promise.resolve()
|
.then(() => {
|
const path = fullPath + "..\\..\\kata-images\\" + filenameWithoutExtension + ".svg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "..\\..\\kata-images\\" + filenameWithoutExtension + ".jpg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "..\\..\\kata-images\\" + filenameWithoutExtension + ".png";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + filename;
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + filenameWithoutExtension + ".svg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + filenameWithoutExtension + ".jpg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + filenameWithoutExtension + ".png";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "_autogen" + "\\" + filenameWithoutExtension + ".svg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "_autogen" + "\\" + filenameWithoutExtension + ".jpg";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "_autogen" + "\\" + filenameWithoutExtension + ".png";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const decodedFilename = decodeURIComponent(filenameWithoutExtension);
|
const path = fullPath + "_autogen" + "\\" + decodedFilename + ".png";
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = getFittingFilenameByWildcard(fullPath, filenameWithoutExtension);
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "photos" + "\\" + filename;
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.catch(() => {
|
const path = fullPath + "placeproposals" + "\\" + filename;
|
return Promise.join(fs.statAsync(path), path);
|
})
|
.spread(async (stat, path) => {
|
const acceptsGzip = req.headers["accept-encoding"] && (/gzip/ig).test(req.headers["accept-encoding"]);
|
|
let extension = path.replace(/.+\.(.+)/, "$1");
|
|
if (extension === "svg") {
|
extension = "svg+xml";
|
}
|
|
const newHeaders = {
|
"content-type": "image/" + extension,
|
"etag": etag(stat),
|
"last-modified": stat.mtime.toUTCString()
|
};
|
|
if (acceptsGzip) {
|
newHeaders["content-encoding"] = "gzip";
|
}
|
|
res.set(newHeaders);
|
|
if (fresh(req.headers, newHeaders)) {
|
return res.status(304).end();
|
}
|
else {
|
const stat = await fs.statAsync(path);
|
|
if (stat.isDirectory()) {
|
Winston.warn(`Unable to serve directory as a file: ${path}`);
|
|
res.removeHeader("content-type");
|
res.removeHeader("content-encoding");
|
res.removeHeader("etag");
|
res.removeHeader("last-modified");
|
|
return res.status(404).send("not found");
|
}
|
|
let stream = fs.createReadStream(path);
|
|
stream.on("error", (error) => {
|
Winston.warn(`Error while reading file: ${path}`, error);
|
|
return res.end();
|
});
|
|
if (acceptsGzip) {
|
stream = stream.pipe(zlib.createGzip());
|
}
|
|
stream.pipe(res);
|
}
|
})
|
.catch((error) => {
|
|
if (req.query.placeholder && req.query.placeholder === "false") {
|
return res.status(404).end();
|
}
|
|
let buffer;
|
|
// 1x1 transparent png
|
const commonPlaceholder = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8Xw8AAoMBgDTD2qgAAAAASUVORK5CYII=";
|
|
// grey landscape article place holder
|
const articlePlaceholder = "iVBORw0KGgoAAAANSUhEUgAAAGcAAABYCAIAAABnD37WAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIVERUIrtVDhQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD4ElEQVR42u2da3uiOhDHJ7FoS12x1daF4/f/YkejyEWRq2DIebHt6e6z60pAWzAzr+ERfsw/c8lFIoQANEmjiACpITWkhtTQkBpS+zS7q37pIfTCOMtLcqssSH9gGBNdq3BllSzXY4uDSl7Z083ZmDSgdtyzTaSgBksw5tZjrXGtjNREBgAUggWL61BzV4HagTKw97LU4k1OCKhtPFrJUQu3OWYYAMItpKhRTOUAAHJXVKd2RF5vzlaKRlnuD3u1rLubxLO3WcSxosI6FKkhNcmR9VZmdq47sh9D1wtzfrLHYJjTR6T2S2nBgjPpi8gDxgLoT6zpABUKpbM8i+ynPNJbsJ3y1FJ3XRDJh0iWNleamuMfatxFuB2rSy2xi7qdkh0rFKVW+PXfnICrKLVdo5acSBX1tWaNzISrSK1pf+kYK+lrWIeifRK1prMzvQcVqfWaVsV3Sir0uSyb3D4mSlK7H2m17y3LsarRYPRS+9aHma5sDKVWv56j6ROtK9Cu0ZWcWgZbBHLfg5jzRvLke3sT8Z/76yUZzs1Rl/K1R2s+JtXDQu/VMhtE33TFmP0rMgCgImLsWk27a2W5ujm3rIlG/j69Qu6GpmXN6jv8ds3Y9vRv8PXS7YhCP2zwYv7zVtUnwT49/p/LPo315p+rcJbOuaYxIfmCFXNL6xC1D9N0Y3LRCJlt/vWPvWpqcrzCumyo6WQdmjmLisjeEV9Yp92jVjpLv5B7bEJyN1WYWuksZSfA3tzN23WPmhDiAssVok09ZABAaeJfbjLnutFgu16mf9jVQXrDyWzUl0XG9o16xYmdPM/1dlOLXRbkJzpugkcuiwCg9zidGVXohTYLm2aslO4y0O/bq9Bow4Iqi6F57DLGVn58JmI2R/bm+9vWKrSMJKUksoCx4A+yfa8uL/ZpebyFp6c2Ulut9/UCxrtsr2iUpik8PbRNoRlbtHxh385v27hWeH7rE0CehO2i5myy9ufJlLaK2nZVdGTflVu0hpqTlNARO7hlO6jFm6I7G/wED1pBbdepDX6UprwF1LKkaxv8dvzLqV2qTvlEy4OvphbGvHPUeJJ9LbVjF/ffUrr9Ump7DzppoolAGlfvo5k1AtUM10oiNaR2U9T4rZKQWeV5KhqcLCo9xtDXTvlajyCbH241pBIKnQKePgwAoBsy45qmYBr2eyos+t8ko8G3ZygVp3b/OpWOoffWvK/wKeFC+35q1dvZcyWFu2QKHsRGBqY5OfnWlU7jLPyVk6nidIJoU/Pl70dlEKkFUofQi270MDshBsZkqFUTFcH/N8A6FKkhNaSGhtSQGlJrtf0HiryeJV1E7dYAAAAASUVORK5CYII=";
|
|
if (req.params.type === "art") {
|
buffer = Buffer.from(articlePlaceholder, "base64");
|
}
|
else {
|
buffer = Buffer.from(commonPlaceholder, "base64");
|
}
|
|
const newHeaders = {
|
"content-type": "image/png",
|
"content-length": buffer.length,
|
"etag": etag(buffer),
|
"last-modified": new Date(0) // 01.01.1970
|
};
|
|
res.set(newHeaders);
|
|
if (fresh(req.headers, newHeaders)) {
|
return res.status(304).end();
|
}
|
else {
|
return res.send(buffer);
|
}
|
});
|
});
|
|
module.exports = router;
|