Added a logger and installed a number of new dependencies to support it.Added fetch-node for the client
This commit is contained in:
parent
86afae2683
commit
8ff6b4ffdb
|
@ -1,3 +1,4 @@
|
|||
YOLO_WEB_URL=http://localhost:3333
|
||||
DATASETS=./datasets
|
||||
JOB_DELAY=0
|
||||
APP_NAME=yolo_web
|
|
@ -14,12 +14,14 @@ const body_parser_1 = __importDefault(require("body-parser"));
|
|||
const multer_1 = __importDefault(require("multer"));
|
||||
const uuid_1 = require("uuid");
|
||||
const mime_1 = require("mime");
|
||||
const log_1 = require("./log");
|
||||
const port = typeof process.env['PORT'] !== 'undefined' ? parseInt(process.env['PORT'], 10) : 3333;
|
||||
const data = typeof process.env['DATADIR'] !== 'undefined' ? process.env['DATADIR'] : './data';
|
||||
const dbPath = (0, path_1.join)(data, 'queue.sqlite');
|
||||
const app = (0, express_1.default)();
|
||||
const tmp = (0, os_1.tmpdir)();
|
||||
const db = new sqlite3_1.Database(dbPath);
|
||||
let log;
|
||||
const accepted = ['application/zip', 'application/x-zip-compressed'];
|
||||
const storage = multer_1.default.diskStorage({
|
||||
destination: function (req, file, cb) {
|
||||
|
@ -34,7 +36,7 @@ function fileFilter(req, file, cb) {
|
|||
cb(null, true);
|
||||
}
|
||||
else {
|
||||
console.warn(`Filetype ${file.mimetype} is not of type zip`);
|
||||
log.warn(`Filetype ${file.mimetype} is not of type zip`);
|
||||
cb(new Error("Dataset is not of type zip"), false);
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +71,7 @@ async function add(email, name, dataset, model) {
|
|||
return db.run(query, [id, email, name, dataset, model], (err, row) => {
|
||||
if (err)
|
||||
return reject(err);
|
||||
console.log(`Added job ${id} to queue`);
|
||||
log.info(`Added job ${id} to queue`);
|
||||
return resolve(id);
|
||||
});
|
||||
});
|
||||
|
@ -97,7 +99,7 @@ async function status(id) {
|
|||
else if (rows[0].started !== null) {
|
||||
jobStatus = `Started ${rows[0].started}`;
|
||||
}
|
||||
console.log(`Got status for job ${id}: ${jobStatus}`);
|
||||
log.info(`Got status for job ${id}: ${jobStatus}`);
|
||||
return resolve(jobStatus);
|
||||
});
|
||||
});
|
||||
|
@ -207,7 +209,7 @@ app.get('/', async (req, res, next) => {
|
|||
html = await promises_1.default.readFile('./views/index.html', 'utf8');
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
res.send(html);
|
||||
|
@ -219,14 +221,14 @@ app.post('/', uploadZip.single('dataset'), async (req, res, next) => {
|
|||
let id;
|
||||
req.setTimeout(0);
|
||||
if (typeof req.file === 'undefined' || req.file === null) {
|
||||
console.error('No file in upload');
|
||||
log.error('No file in upload');
|
||||
return next('ERROR: Please upload dataset as zip file');
|
||||
}
|
||||
try {
|
||||
fileHash = await hash(req.file.path);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error hashing file ${req.file.originalname}`);
|
||||
}
|
||||
filePath = (0, path_1.join)(data, `${fileHash}.zip`);
|
||||
|
@ -234,32 +236,32 @@ app.post('/', uploadZip.single('dataset'), async (req, res, next) => {
|
|||
fileExists = await exists(filePath);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
if (!fileExists) {
|
||||
try {
|
||||
await promises_1.default.copyFile(req.file.path, filePath);
|
||||
console.log(`Saved dataset with hash ${fileHash}`);
|
||||
log.info(`Saved dataset with hash ${fileHash}`);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn(`Dataset with hash ${fileHash} already exists...`);
|
||||
log.warn(`Dataset with hash ${fileHash} already exists...`);
|
||||
}
|
||||
try {
|
||||
await promises_1.default.unlink(req.file.path);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
try {
|
||||
id = await add(req.body.email, req.body.name, fileHash, req.body.model);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
log.info(err);
|
||||
return next(`Error adding training job ${req.body.name}`);
|
||||
}
|
||||
res.send(`<html><body>Dataset for job ${req.body.name} has been uploaded successfully. You will be emailed when your job has started and when it has completed training. <br /> Monitor job status here: <a href="/job/${id}">${id}</a></body></html>`);
|
||||
|
@ -270,7 +272,7 @@ app.post('/job/:id', uploadOnnx.single('model'), async (req, res, next) => {
|
|||
let id;
|
||||
req.setTimeout(0);
|
||||
if (typeof req.file === 'undefined' || req.file === null) {
|
||||
console.error('No file in upload');
|
||||
log.error('No file in upload');
|
||||
return next('ERROR: Please model as zip file');
|
||||
}
|
||||
id = req.params.id;
|
||||
|
@ -280,23 +282,23 @@ app.post('/job/:id', uploadOnnx.single('model'), async (req, res, next) => {
|
|||
}
|
||||
try {
|
||||
await promises_1.default.copyFile(req.file.path, filePath);
|
||||
console.log(`Saved model for job ${id}`);
|
||||
log.info(`Saved model for job ${id}`);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
try {
|
||||
await promises_1.default.unlink(req.file.path);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
try {
|
||||
await complete(id, meta);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
log.error(err);
|
||||
return next(`Error completing training job ${id}`);
|
||||
}
|
||||
res.json({ id });
|
||||
|
@ -304,18 +306,18 @@ app.post('/job/:id', uploadOnnx.single('model'), async (req, res, next) => {
|
|||
app.get('/job/:id', async (req, res, next) => {
|
||||
let jobStatus;
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No job id provided`);
|
||||
log.error(`No job id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
if (req.params.id.length !== 36) {
|
||||
console.error(`Job id ${req.params.id} is invalid`);
|
||||
log.error(`Job id ${req.params.id} is invalid`);
|
||||
return next('Invalid job id');
|
||||
}
|
||||
try {
|
||||
jobStatus = await status(req.params.id);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job status');
|
||||
}
|
||||
return res.send(`<html><body>Job: ${req.params.id}<br /> Status: ${jobStatus}</body></html>`);
|
||||
|
@ -329,7 +331,7 @@ app.get('/model/:id', async (req, res, next) => {
|
|||
let mimeType;
|
||||
let stream;
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No job id provided`);
|
||||
log.error(`No job id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
id = req.params.id;
|
||||
|
@ -338,18 +340,18 @@ app.get('/model/:id', async (req, res, next) => {
|
|||
fileExists = await exists(filePath);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error checking whether model for job ${id} exists`);
|
||||
}
|
||||
if (!fileExists) {
|
||||
console.warn(`Model for job ${id} does not exist`);
|
||||
log.warn(`Model for job ${id} does not exist`);
|
||||
return next(`Model for job ${id} does not exist`);
|
||||
}
|
||||
try {
|
||||
fileName = await name(id);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error getting job ${id}`);
|
||||
}
|
||||
mimeType = (0, mime_1.getType)(filePath);
|
||||
|
@ -367,7 +369,7 @@ app.get('/dataset/:id', async (req, res, next) => {
|
|||
let mimeType;
|
||||
let stream;
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
id = req.params.id;
|
||||
|
@ -375,7 +377,7 @@ app.get('/dataset/:id', async (req, res, next) => {
|
|||
datasetHash = await dataset(id);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error getting dataset for job ${id}`);
|
||||
}
|
||||
filePath = (0, path_1.join)(data, `${datasetHash}.zip`);
|
||||
|
@ -383,11 +385,11 @@ app.get('/dataset/:id', async (req, res, next) => {
|
|||
fileExists = await exists(filePath);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error checking whether dataset for job ${id} exists`);
|
||||
}
|
||||
if (!fileExists) {
|
||||
console.warn(`Dataset for job ${id} does not exist`);
|
||||
log.warn(`Dataset for job ${id} does not exist`);
|
||||
return next(`Dataset for job ${id} does not exist`);
|
||||
}
|
||||
mimeType = (0, mime_1.getType)(filePath);
|
||||
|
@ -402,7 +404,7 @@ app.get('/job', async (req, res, next) => {
|
|||
jobArr = await job();
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job');
|
||||
}
|
||||
res.json(jobArr);
|
||||
|
@ -413,7 +415,7 @@ app.get('/jobs', async (req, res, next) => {
|
|||
jobArr = await jobs();
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job');
|
||||
}
|
||||
res.json(jobArr);
|
||||
|
@ -423,16 +425,16 @@ app.post('/job/claim/:id', async (req, res, next) => {
|
|||
let jobObj;
|
||||
let resObj = {};
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
id = req.params.id;
|
||||
try {
|
||||
jobObj = await claim(id);
|
||||
console.log(`Job ${id} was claimed`);
|
||||
log.info(`Job ${id} was claimed`);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error claiming job');
|
||||
}
|
||||
resObj.id = id;
|
||||
|
@ -447,7 +449,7 @@ app.post('/job/fail/:id', async (req, res, next) => {
|
|||
let id;
|
||||
let meta = null;
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
id = req.params.id;
|
||||
|
@ -456,15 +458,16 @@ app.post('/job/fail/:id', async (req, res, next) => {
|
|||
}
|
||||
try {
|
||||
await fail(id, meta);
|
||||
console.log(`Job ${id} failed`);
|
||||
log.info(`Job ${id} failed`);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error failing job');
|
||||
}
|
||||
res.json(true);
|
||||
});
|
||||
app.listen(port, () => {
|
||||
console.log(`yolo_web running on port ${port}`);
|
||||
log = (0, log_1.createLog)('server');
|
||||
log.info(`yolo_web running on port ${port}`);
|
||||
});
|
||||
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createLog = void 0;
|
||||
/** @module log */
|
||||
/** Wrapper for winston that tags streams and optionally writes files with a simple interface. */
|
||||
/** Module now also supports optional papertrail integration, other services to follow */
|
||||
const winston_1 = require("winston");
|
||||
const { SPLAT } = require('triple-beam');
|
||||
const { isObject } = require('lodash');
|
||||
const APP_NAME = process.env.APP_NAME || 'default';
|
||||
let winstonPapertrail;
|
||||
function formatObject(param) {
|
||||
if (isObject(param)) {
|
||||
return JSON.stringify(param);
|
||||
}
|
||||
return param;
|
||||
}
|
||||
const all = (0, winston_1.format)((info) => {
|
||||
const splat = info[SPLAT] || [];
|
||||
const message = formatObject(info.message);
|
||||
const rest = splat.map(formatObject).join(' ');
|
||||
info.message = `${message} ${rest}`;
|
||||
return info;
|
||||
});
|
||||
const myFormat = winston_1.format.printf(({ level, message, label, timestamp }) => {
|
||||
return `${timestamp} [${label}] ${level}: ${message}`;
|
||||
});
|
||||
/**
|
||||
* Returns a winston logger configured to service
|
||||
*
|
||||
* @param {string} label Label appearing on logger
|
||||
* @param {string} filename Optional file to write log to
|
||||
*
|
||||
* @returns {object} Winston logger
|
||||
*/
|
||||
function createLog(label, filename = null) {
|
||||
const tports = [new (winston_1.transports.Console)()];
|
||||
const fmat = winston_1.format.combine(all(), winston_1.format.label({ label }), winston_1.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }), winston_1.format.colorize(), myFormat);
|
||||
let papertrailOpts;
|
||||
if (filename !== null) {
|
||||
tports.push(new (winston_1.transports.File)({ filename }));
|
||||
}
|
||||
return (0, winston_1.createLogger)({
|
||||
format: fmat,
|
||||
transports: tports
|
||||
});
|
||||
}
|
||||
exports.createLog = createLog;
|
||||
module.exports = { createLog };
|
||||
//# sourceMappingURL=log.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;;AAEZ,kBAAkB;AAClB,iGAAiG;AACjG,yFAAyF;AAEzF,qCAA2D;AAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AACzC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvC,MAAM,QAAQ,GAAY,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,SAAS,CAAC;AAE5D,IAAI,iBAAiB,CAAC;AAEtB,SAAS,YAAY,CAAE,KAAW;IAChC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE;QACnB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;KAC9B;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,GAAG,GAAG,IAAA,gBAAM,EAAC,CAAC,IAAU,EAAE,EAAE;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,GAAG,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;IACpC,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,gBAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAQ,EAAE,EAAE;IAC5E,OAAO,GAAG,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK,OAAO,EAAE,CAAC;AACxD,CAAC,CAAC,CAAC;AAEH;;;;;;;EAOE;AACF,SAAgB,SAAS,CAAE,KAAc,EAAE,WAAoB,IAAI;IAC/D,MAAM,MAAM,GAAW,CAAE,IAAI,CAAC,oBAAU,CAAC,OAAO,CAAC,EAAE,CAAE,CAAC;IACtD,MAAM,IAAI,GAAS,gBAAM,CAAC,OAAO,CAC7B,GAAG,EAAE,EACL,gBAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,EACvB,gBAAM,CAAC,SAAS,CAAC,EAAC,MAAM,EAAE,yBAAyB,EAAC,CAAC,EACrD,gBAAM,CAAC,QAAQ,EAAE,EACjB,QAAQ,CACX,CAAC;IACF,IAAI,cAAoB,CAAC;IAEzB,IAAI,QAAQ,KAAK,IAAI,EAAE;QACnB,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,oBAAU,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAE,CAAC;KACtD;IAED,OAAO,IAAA,sBAAY,EAAC;QAChB,MAAM,EAAG,IAAI;QACb,UAAU,EAAG,MAAM;KACtB,CAAC,CAAC;AACP,CAAC;AAnBD,8BAmBC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,SAAS,EAAE,CAAC"}
|
|
@ -11,20 +11,44 @@
|
|||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.18.2",
|
||||
"lodash": "^4.17.21",
|
||||
"mime": "^3.0.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"sqlite3": "^5.1.6",
|
||||
"uuid": "^9.0.0"
|
||||
"triple-beam": "^1.4.1",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/mime": "^3.0.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node-fetch": "^2.6.9",
|
||||
"@types/sqlite3": "^3.1.8",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@types/winston": "^2.4.4",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
||||
"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/@dabh/diagnostics": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
|
||||
"integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
|
||||
"dependencies": {
|
||||
"colorspace": "1.1.x",
|
||||
"enabled": "2.0.x",
|
||||
"kuler": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@gar/promisify": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
||||
|
@ -50,6 +74,25 @@
|
|||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@npmcli/fs": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz",
|
||||
|
@ -153,6 +196,16 @@
|
|||
"integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
|
@ -201,12 +254,27 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/triple-beam": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz",
|
||||
"integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/winston": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz",
|
||||
"integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==",
|
||||
"deprecated": "This is a stub types definition. winston provides its own type definitions, so you do not need this installed.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"winston": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
|
@ -341,6 +409,17 @@
|
|||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
|
||||
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
@ -460,6 +539,37 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.3",
|
||||
"color-string": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
|
@ -468,6 +578,27 @@
|
|||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/colorspace": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
||||
"integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
|
||||
"dependencies": {
|
||||
"color": "^3.1.3",
|
||||
"text-hex": "1.0.x"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
@ -556,6 +687,14 @@
|
|||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
@ -564,6 +703,15 @@
|
|||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
|
@ -604,6 +752,11 @@
|
|||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/enabled": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
|
@ -739,6 +892,33 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fecha": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
|
@ -756,6 +936,36 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fn.name": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
|
||||
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
@ -1052,6 +1262,11 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
|
@ -1066,6 +1281,17 @@
|
|||
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
|
@ -1077,6 +1303,37 @@
|
|||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/logform": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz",
|
||||
"integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==",
|
||||
"dependencies": {
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/triple-beam": "^1.3.2",
|
||||
"fecha": "^4.2.0",
|
||||
"ms": "^2.1.1",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"triple-beam": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/logform/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
|
@ -1352,23 +1609,39 @@
|
|||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
|
||||
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp": {
|
||||
|
@ -1502,6 +1775,14 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/one-time": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
|
||||
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
|
||||
"dependencies": {
|
||||
"fn.name": "1.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
|
@ -1665,6 +1946,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/safe-stable-stringify": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
|
||||
"integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
|
@ -1765,6 +2054,14 @@
|
|||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
|
@ -1860,6 +2157,14 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
|
@ -1932,6 +2237,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
|
@ -1945,6 +2255,14 @@
|
|||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/triple-beam": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
|
||||
"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
@ -2030,6 +2348,14 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
|
||||
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
@ -2067,6 +2393,40 @@
|
|||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/winston": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz",
|
||||
"integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==",
|
||||
"dependencies": {
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@dabh/diagnostics": "^2.0.2",
|
||||
"async": "^3.2.3",
|
||||
"is-stream": "^2.0.0",
|
||||
"logform": "^2.4.0",
|
||||
"one-time": "^1.0.0",
|
||||
"readable-stream": "^3.4.0",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"stack-trace": "0.0.x",
|
||||
"triple-beam": "^1.3.0",
|
||||
"winston-transport": "^4.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/winston-transport": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz",
|
||||
"integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==",
|
||||
"dependencies": {
|
||||
"logform": "^2.3.2",
|
||||
"readable-stream": "^3.6.0",
|
||||
"triple-beam": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
|
|
@ -14,16 +14,22 @@
|
|||
"@types/express": "^4.17.17",
|
||||
"@types/mime": "^3.0.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node-fetch": "^2.6.9",
|
||||
"@types/sqlite3": "^3.1.8",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@types/winston": "^2.4.4",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.18.2",
|
||||
"lodash": "^4.17.21",
|
||||
"mime": "^3.0.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"sqlite3": "^5.1.6",
|
||||
"uuid": "^9.0.0"
|
||||
"triple-beam": "^1.4.1",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.11.0"
|
||||
}
|
||||
}
|
||||
|
|
78
src/index.ts
78
src/index.ts
|
@ -10,6 +10,8 @@ import bodyParser from 'body-parser';
|
|||
import multer from 'multer';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { getType } from 'mime';
|
||||
import { createLog } from './log'
|
||||
import type { Logger } from 'winston';
|
||||
|
||||
const port : number = typeof process.env['PORT'] !== 'undefined' ? parseInt(process.env['PORT'], 10) : 3333;
|
||||
const data : string = typeof process.env['DATADIR'] !== 'undefined' ? process.env['DATADIR'] : './data';
|
||||
|
@ -17,6 +19,7 @@ const dbPath : string = join(data, 'queue.sqlite');
|
|||
const app : Express = express();
|
||||
const tmp : string = tmpdir();
|
||||
const db : Database = new Database(dbPath);
|
||||
let log : Logger = createLog('server');
|
||||
|
||||
const accepted : string[] = ['application/zip', 'application/x-zip-compressed'];
|
||||
|
||||
|
@ -33,7 +36,7 @@ function fileFilter (req: any, file: any, cb: any) {
|
|||
if (accepted.indexOf(file.mimetype) !== -1) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
console.warn(`Filetype ${file.mimetype} is not of type zip`);
|
||||
log.warn(`Filetype ${file.mimetype} is not of type zip`);
|
||||
cb(new Error("Dataset is not of type zip"), false);
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +74,7 @@ async function add (email : string, name : string, dataset : string, model : str
|
|||
return new Promise((resolve : Function, reject : Function) => {
|
||||
return db.run(query, [id, email, name, dataset, model], (err : Error, row : any) => {
|
||||
if (err) return reject(err);
|
||||
console.log(`Added job ${id} to queue`);
|
||||
log.info(`Added job ${id} to queue`);
|
||||
return resolve(id);
|
||||
});
|
||||
});
|
||||
|
@ -96,7 +99,7 @@ async function status (id : string) : Promise<string> {
|
|||
} else if (rows[0].started !== null) {
|
||||
jobStatus = `Started ${rows[0].started}`;
|
||||
}
|
||||
console.log(`Got status for job ${id}: ${jobStatus}`);
|
||||
log.info(`Got status for job ${id}: ${jobStatus}`);
|
||||
return resolve(jobStatus);
|
||||
});
|
||||
});
|
||||
|
@ -205,7 +208,7 @@ app.get('/', async (req : Request, res : Response, next : NextFunction) => {
|
|||
try {
|
||||
html = await fs.readFile('./views/index.html', 'utf8');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
res.send(html);
|
||||
|
@ -220,14 +223,14 @@ app.post('/', uploadZip.single('dataset'), async (req : Request, res : Response,
|
|||
req.setTimeout(0);
|
||||
|
||||
if (typeof req.file === 'undefined' || req.file === null) {
|
||||
console.error('No file in upload');
|
||||
log.error('No file in upload');
|
||||
return next('ERROR: Please upload dataset as zip file');
|
||||
}
|
||||
|
||||
try {
|
||||
fileHash = await hash(req.file.path);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error hashing file ${req.file.originalname}`);
|
||||
}
|
||||
|
||||
|
@ -235,31 +238,31 @@ app.post('/', uploadZip.single('dataset'), async (req : Request, res : Response,
|
|||
try {
|
||||
fileExists = await exists(filePath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
|
||||
if (!fileExists) {
|
||||
try {
|
||||
await fs.copyFile(req.file.path, filePath);
|
||||
console.log(`Saved dataset with hash ${fileHash}`);
|
||||
log.info(`Saved dataset with hash ${fileHash}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Dataset with hash ${fileHash} already exists...`);
|
||||
log.warn(`Dataset with hash ${fileHash} already exists...`);
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.unlink(req.file.path);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
id = await add(req.body.email, req.body.name, fileHash, req.body.model);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
log.info(err);
|
||||
return next(`Error adding training job ${req.body.name}`);
|
||||
}
|
||||
|
||||
|
@ -274,7 +277,7 @@ app.post('/job/:id', uploadOnnx.single('model'), async (req : Request, res : Res
|
|||
req.setTimeout(0);
|
||||
|
||||
if (typeof req.file === 'undefined' || req.file === null) {
|
||||
console.error('No file in upload');
|
||||
log.error('No file in upload');
|
||||
return next('ERROR: Please model as zip file');
|
||||
}
|
||||
|
||||
|
@ -286,22 +289,22 @@ app.post('/job/:id', uploadOnnx.single('model'), async (req : Request, res : Res
|
|||
|
||||
try {
|
||||
await fs.copyFile(req.file.path, filePath);
|
||||
console.log(`Saved model for job ${id}`);
|
||||
log.info(`Saved model for job ${id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(err);
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.unlink(req.file.path);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
}
|
||||
|
||||
try {
|
||||
await complete(id, meta);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
log.error(err);
|
||||
return next(`Error completing training job ${id}`);
|
||||
}
|
||||
|
||||
|
@ -312,19 +315,19 @@ app.get('/job/:id', async (req : Request, res : Response, next : NextFunction) =
|
|||
let jobStatus : string;
|
||||
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No job id provided`);
|
||||
log.error(`No job id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
|
||||
if (req.params.id.length !== 36) {
|
||||
console.error(`Job id ${req.params.id} is invalid`);
|
||||
log.error(`Job id ${req.params.id} is invalid`);
|
||||
return next('Invalid job id');
|
||||
}
|
||||
|
||||
try {
|
||||
jobStatus = await status(req.params.id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job status');
|
||||
}
|
||||
return res.send(`<html><body>Job: ${req.params.id}<br /> Status: ${jobStatus}</body></html>`);
|
||||
|
@ -340,7 +343,7 @@ app.get('/model/:id', async (req : Request, res: Response, next : NextFunction)
|
|||
let stream : any;
|
||||
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No job id provided`);
|
||||
log.error(`No job id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
|
||||
|
@ -349,17 +352,17 @@ app.get('/model/:id', async (req : Request, res: Response, next : NextFunction)
|
|||
try {
|
||||
fileExists = await exists(filePath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error checking whether model for job ${id} exists`);
|
||||
}
|
||||
if (!fileExists) {
|
||||
console.warn(`Model for job ${id} does not exist`)
|
||||
log.warn(`Model for job ${id} does not exist`)
|
||||
return next(`Model for job ${id} does not exist`);
|
||||
}
|
||||
try {
|
||||
fileName = await name(id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error getting job ${id}`);
|
||||
}
|
||||
mimeType = getType(filePath);
|
||||
|
@ -381,7 +384,7 @@ app.get('/dataset/:id', async (req : Request, res: Response, next : NextFunction
|
|||
let stream : any;
|
||||
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
|
||||
|
@ -390,7 +393,7 @@ app.get('/dataset/:id', async (req : Request, res: Response, next : NextFunction
|
|||
try {
|
||||
datasetHash = await dataset(id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error getting dataset for job ${id}`);
|
||||
}
|
||||
|
||||
|
@ -399,11 +402,11 @@ app.get('/dataset/:id', async (req : Request, res: Response, next : NextFunction
|
|||
try {
|
||||
fileExists = await exists(filePath);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next(`Error checking whether dataset for job ${id} exists`);
|
||||
}
|
||||
if (!fileExists) {
|
||||
console.warn(`Dataset for job ${id} does not exist`)
|
||||
log.warn(`Dataset for job ${id} does not exist`)
|
||||
return next(`Dataset for job ${id} does not exist`);
|
||||
}
|
||||
|
||||
|
@ -422,7 +425,7 @@ app.get('/job', async (req : Request, res: Response, next : NextFunction) => {
|
|||
try {
|
||||
jobArr = await job();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job');
|
||||
}
|
||||
|
||||
|
@ -435,7 +438,7 @@ app.get('/jobs', async (req : Request, res: Response, next : NextFunction) => {
|
|||
try {
|
||||
jobArr = await jobs();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error getting job');
|
||||
}
|
||||
|
||||
|
@ -448,7 +451,7 @@ app.post('/job/claim/:id', async (req : Request, res: Response, next : NextFunct
|
|||
let resObj : any = {};
|
||||
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
|
||||
|
@ -456,9 +459,9 @@ app.post('/job/claim/:id', async (req : Request, res: Response, next : NextFunct
|
|||
|
||||
try {
|
||||
jobObj = await claim(id);
|
||||
console.log(`Job ${id} was claimed`);
|
||||
log.info(`Job ${id} was claimed`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error claiming job');
|
||||
}
|
||||
|
||||
|
@ -477,7 +480,7 @@ app.post('/job/fail/:id', async (req : Request, res: Response, next : NextFuncti
|
|||
let meta : string = null;
|
||||
|
||||
if (typeof req.params.id === 'undefined' || req.params.id === null) {
|
||||
console.error(`No dataset id provided`);
|
||||
log.error(`No dataset id provided`);
|
||||
return next('Invalid request');
|
||||
}
|
||||
|
||||
|
@ -488,9 +491,9 @@ app.post('/job/fail/:id', async (req : Request, res: Response, next : NextFuncti
|
|||
|
||||
try {
|
||||
await fail(id, meta);
|
||||
console.log(`Job ${id} failed`);
|
||||
log.info(`Job ${id} failed`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
log.error(err);
|
||||
return next('Error failing job');
|
||||
}
|
||||
|
||||
|
@ -498,5 +501,6 @@ app.post('/job/fail/:id', async (req : Request, res: Response, next : NextFuncti
|
|||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`yolo_web running on port ${port}`);
|
||||
|
||||
log.info(`yolo_web running on port ${port}`);
|
||||
})
|
|
@ -0,0 +1,63 @@
|
|||
'use strict'
|
||||
|
||||
/** @module log */
|
||||
/** Wrapper for winston that tags streams and optionally writes files with a simple interface. */
|
||||
/** Module now also supports optional papertrail integration, other services to follow */
|
||||
|
||||
import { format, transports, createLogger } from 'winston';
|
||||
const { SPLAT } = require('triple-beam');
|
||||
const { isObject } = require('lodash');
|
||||
|
||||
const APP_NAME : string = process.env.APP_NAME || 'default';
|
||||
|
||||
let winstonPapertrail;
|
||||
|
||||
function formatObject (param : any) {
|
||||
if (isObject(param)) {
|
||||
return JSON.stringify(param);
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
const all = format((info : any) => {
|
||||
const splat = info[SPLAT] || [];
|
||||
const message = formatObject(info.message);
|
||||
const rest = splat.map(formatObject).join(' ');
|
||||
info.message = `${message} ${rest}`;
|
||||
return info;
|
||||
});
|
||||
|
||||
const myFormat = format.printf(({ level, message, label, timestamp } : any) => {
|
||||
return `${timestamp} [${label}] ${level}: ${message}`;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a winston logger configured to service
|
||||
*
|
||||
* @param {string} label Label appearing on logger
|
||||
* @param {string} filename Optional file to write log to
|
||||
*
|
||||
* @returns {object} Winston logger
|
||||
*/
|
||||
export function createLog (label : string, filename : string = null) {
|
||||
const tports : any[] = [ new (transports.Console)() ];
|
||||
const fmat : any = format.combine(
|
||||
all(),
|
||||
format.label({ label }),
|
||||
format.timestamp({format: 'YYYY-MM-DD HH:mm:ss.SSS'}),
|
||||
format.colorize(),
|
||||
myFormat,
|
||||
);
|
||||
let papertrailOpts : any;
|
||||
|
||||
if (filename !== null) {
|
||||
tports.push( new (transports.File)({ filename }) );
|
||||
}
|
||||
|
||||
return createLogger({
|
||||
format : fmat,
|
||||
transports : tports
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { createLog };
|
Loading…
Reference in New Issue