Added a logger and installed a number of new dependencies to support it.Added fetch-node for the client

This commit is contained in:
Matt McWilliams 2023-11-30 19:25:43 -05:00
parent 86afae2683
commit 8ff6b4ffdb
9 changed files with 577 additions and 89 deletions

View File

@ -1,3 +1,4 @@
YOLO_WEB_URL=http://localhost:3333
DATASETS=./datasets
JOB_DELAY=0
APP_NAME=yolo_web

77
dist/index.js vendored
View File

@ -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

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

50
dist/log.js vendored Normal file
View File

@ -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

1
dist/log.js.map vendored Normal file
View File

@ -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"}

386
package-lock.json generated
View File

@ -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",

View File

@ -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"
}
}

View File

@ -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}`);
})

63
src/log.ts Normal file
View File

@ -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 };