feat: Add RFC error messages
Signed-off-by: Florian BOUILLON <f.bouillon@aptatio.com>
This commit is contained in:
parent
e39e3726ac
commit
19e3892099
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "3dprint-time-estimator",
|
||||
"name": "fi3d-slicer-as-a-service",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
54
src/HTTPError.ts
Normal file
54
src/HTTPError.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { Response } from 'express'
|
||||
|
||||
/**
|
||||
* An error as of the RFC7807
|
||||
*
|
||||
* you MUST send the content-type `application/problem+json`
|
||||
*/
|
||||
export default interface HTTPError extends Record<string, any> {
|
||||
/**
|
||||
* A URI reference [RFC3986] that identifies the
|
||||
* problem type. This specification encourages that, when
|
||||
* dereferenced, it provide human-readable documentation for the
|
||||
* problem type (e.g., using HTML [W3C.REC-html5-20141028]). When
|
||||
* this member is not present, its value is assumed to be
|
||||
* "about:blank".
|
||||
*/
|
||||
title: string
|
||||
/**
|
||||
* A short, human-readable summary of the problem
|
||||
* type. It SHOULD NOT change from occurrence to occurrence of the
|
||||
* problem, except for purposes of localization (e.g., using
|
||||
* proactive content negotiation; see [RFC7231], Section 3.4).
|
||||
*/
|
||||
type?: string
|
||||
|
||||
/**
|
||||
* The HTTP status code ([RFC7231], Section 6)
|
||||
* generated by the origin server for this occurrence of the problem.
|
||||
*/
|
||||
status?: number
|
||||
|
||||
/**
|
||||
* A human-readable explanation specific to this
|
||||
* occurrence of the problem.
|
||||
*/
|
||||
detail?: string
|
||||
|
||||
|
||||
/**
|
||||
* A URI reference that identifies the specific
|
||||
* occurrence of the problem. It may or may not yield further
|
||||
* information if dereferenced.
|
||||
*/
|
||||
instance?: string
|
||||
}
|
||||
|
||||
export function createErrorResponse(res: Response, error: HTTPError) {
|
||||
res.status(error.status ?? 500)
|
||||
if (!error.type) {
|
||||
error.type = 'about:blank'
|
||||
}
|
||||
res.setHeader('Content-Type', 'application/problem+json')
|
||||
res.json(error)
|
||||
}
|
64
src/main.ts
64
src/main.ts
@ -1,10 +1,11 @@
|
||||
import { objectMap, objectOmit } from '@dzeio/object-util'
|
||||
import { exec as execAsync } from 'child_process'
|
||||
import express from 'express'
|
||||
import fs from 'fs/promises'
|
||||
import { exec as execAsync } from 'child_process'
|
||||
import { objectMap, objectOmit } from '@dzeio/object-util'
|
||||
import { getParams } from './gcodeUtils'
|
||||
import util from 'util'
|
||||
import { evaluate } from 'mathjs'
|
||||
import util from 'util'
|
||||
import { createErrorResponse } from './HTTPError'
|
||||
import { getParams } from './gcodeUtils'
|
||||
|
||||
const exec = util.promisify(execAsync)
|
||||
const server = express()
|
||||
@ -48,8 +49,12 @@ server.post('/', async (req, res) => {
|
||||
let config = `${path}/configs/` + (req.query?.config ?? 'config') + '.ini'
|
||||
if (!exists(config)) {
|
||||
console.log('request finished in error :(', file)
|
||||
res.status(403).send('Configuration file not existing')
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'Configuration file does not exist',
|
||||
status: 404,
|
||||
detail: `The configuration file you want to use does not exist`,
|
||||
config: req.query?.config ?? 'config'
|
||||
})
|
||||
}
|
||||
const stlPath = `${path}/files/${file}.stl`
|
||||
const gcodePath = `${path}/files/${file}.gcode`
|
||||
@ -74,23 +79,50 @@ server.post('/', async (req, res) => {
|
||||
console.error(e)
|
||||
if (line.includes('Objects could not fit on the bed')) {
|
||||
await fs.rm(stlPath)
|
||||
res.status(403).send('Object is too large')
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'Object is too large to fit on the bed',
|
||||
status: 413,
|
||||
detail: `The object you are trying to slice is too large to fit on the current bed`
|
||||
})
|
||||
} else if (line.includes('No such file')) {
|
||||
await fs.rm(stlPath)
|
||||
res.status(403).send('Configuration file not existing')
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'Configuration file does not exist',
|
||||
status: 404,
|
||||
detail: `The configuration file you want to use does not exist`,
|
||||
config: req.query?.config ?? 'config'
|
||||
})
|
||||
} else if (line.includes('Unknown option')) {
|
||||
await fs.rm(stlPath)
|
||||
res.status(403).send('an override does not exists, please contact an administrator or refer to the documentation')
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'An override does exist',
|
||||
status: 404,
|
||||
detail: `One or more of your overrides are not available in the current slicer`,
|
||||
overrides: overrides
|
||||
|
||||
})
|
||||
} else if (line.includes('ETIMEDOUT') || line.includes('Command failed')) {
|
||||
await fs.rm(stlPath)
|
||||
res.status(403).send('the file is taking too long to process :(')
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'File is taking too long to process',
|
||||
status: 400,
|
||||
detail: `The file you are trying to process is too large (${req.body.length}o) to be processed in less than 60 secs`,
|
||||
fileId: file,
|
||||
config: req.query?.config ?? 'config',
|
||||
fileSize: req.body.length,
|
||||
overrides: overrides
|
||||
})
|
||||
}
|
||||
res.status(500).send(`Error while making the file:<br />${e.toString().replace(cmd, '<i>software</i>').replace(stlPath, `<i>file ${file}</i>`).replace(`${path}/configs/`, '').replace('.ini', '')}`)
|
||||
return
|
||||
return createErrorResponse(res, {
|
||||
title: 'General I/O error',
|
||||
status: 500,
|
||||
detail: `A server error make it impossible to slice the file`,
|
||||
fileId: file,
|
||||
config: req.query?.config ?? 'config',
|
||||
fileSize: req.body.length,
|
||||
overrides: overrides,
|
||||
serverMessage: e.toString().replace(cmd, '<i>software</i>').replace(stlPath, `<i>file ${file}</i>`).replace(`${path}/configs/`, '').replace('.ini', '')
|
||||
})
|
||||
}
|
||||
const gcode = await fs.readFile(gcodePath, 'utf-8')
|
||||
await fs.rm(stlPath)
|
||||
|
Loading…
x
Reference in New Issue
Block a user