Files
MHDMap/server/ImhdClient.js
2022-06-28 13:02:50 +02:00

136 lines
3.8 KiB
JavaScript

import * as fs from 'fs';
import path from "path";
import https from 'https';
import {fileURLToPath} from "url";
import { nanoid } from 'nanoid'
const imhdData = path.dirname(path.dirname(fileURLToPath(import.meta.url))) + '/dist/imhd';
export default class ImhdClient {
constructor() {
fs.mkdirSync(imhdData + '/icons', { recursive: true });
this.cache = {};
this.loadCache();
}
getVehicleData(vehicleId) {
if (this.cache.hasOwnProperty(vehicleId)) {
return this.cache[vehicleId];
} else {
return null;
}
}
async search(phrase) {
let resp = await fetch('https://imhd.sk/ba/api/sk/vyhladavanie?q=' + encodeURIComponent(phrase));
if (!resp.ok) {
return null;
}
try {
return resp.json();
} catch (e) {
return null;
}
}
async downloadVehicleIcon(vehicleId) {
if (this.cache.hasOwnProperty(vehicleId)) {
if (this.cache[vehicleId].type)
return this.cache[vehicleId].url;
}
const randId = nanoid(5);
const iconPath = imhdData + '/icons/' + randId + '.png';
if (fs.existsSync(iconPath)) {
return null;
}
let results = await this.search(vehicleId);
if (!results) {
console.log('Search for vehicle unsuccessful:', vehicleId);
return null;
}
results = results.results || [];
for (let obj of results) {
if ((typeof obj.img) !== 'string' || obj.img.length < 10)
continue;
const urlParts = obj.url.trim().split('/');
if (urlParts.length < 3)
continue;
if (urlParts[2] !== 'vozidlo')
continue;
if (!obj.name.endsWith('#' + vehicleId))
continue;
let matches = obj.img.match(/.*src="([^"]*)".*/);
if (!matches)
continue;
const url = 'https://imhd.sk' + matches[1];
const existing = Object.values(this.cache).find(el => el.url === url);
if (!existing) {
// TODO: Path traversal vulnerability here!
await this.downloadFile(url, iconPath);
fs.appendFile(
imhdData + '/names.txt',
vehicleId + '|' + obj.name + "\n",
err => { err && console.error(err); }
);
}
this.cache[vehicleId] = {
img: existing ? existing.img : randId,
url: url,
type: obj.class,
info: obj.url,
};
this.saveCache();
return true;
}
}
async downloadFile(url, target) {
return new Promise ((resolve, reject) => {
const file = fs.createWriteStream(target);
https.get(url, resp => {
resp.pipe(file);
file.on('finish', () => {
file.close();
console.log('Downloaded', url);
resolve();
});
});
});
}
loadCache() {
try {
let cacheFile = fs.readFileSync(imhdData + '/iconsdb.json');
if (cacheFile) {
let parsed = JSON.parse(cacheFile);
if (parsed) {
this.cache = parsed;
}
}
} catch (e) {
console.log('Cannot read iconsdb.json for ImhdClient', e);
}
}
saveCache() {
fs.writeFile(imhdData + '/iconsdb.json', JSON.stringify(this.cache, null, 2), err => {
if (err) {
console.log('Cannot save cache for ImhdClient', err);
}
});
}
}