getImage.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. 'use strict'
  2. import express from 'express'
  3. import path from 'path'
  4. import boom from 'boom'
  5. import { imagesPath, imageServedUrl } from '../../config'
  6. import { asyncMiddleware, checkSceneName, checkRequiredParameters, getSceneFilesData } from '../functions'
  7. const router = express.Router()
  8. /**
  9. * @api {get} /getImage?sceneName=:sceneName&imageQuality=:imageQuality Get an image from a scene
  10. * @apiVersion 0.1.0
  11. * @apiName GetImage
  12. * @apiGroup API
  13. *
  14. * @apiDescription Get an image from a scene with the required quality
  15. *
  16. * @apiParam {String} sceneName The selected scene
  17. * @apiParam {Number} imageQuality The required quality of the image
  18. *
  19. * @apiHeader (Response Headers) {String} Content-Type application/json; charset=utf-8
  20. *
  21. * @apiExample Usage example
  22. * curl -i -L -X GET "http://localhost:5000/api/getImage?sceneName=bathroom&imageQuality=200"
  23. *
  24. * @apiSuccess {String} data Path to the image
  25. * @apiSuccessExample {json} Success response example
  26. * HTTP/1.1 200 OK /api/getImage?sceneName=bathroom&imageQuality=200
  27. * {
  28. * "data": "/api/images/bathroom/bathroom_00200.png"
  29. * }
  30. *
  31. * @apiError (Error 4xx) 400 Missing parameter(s)
  32. * @apiErrorExample {json} Missing parameter
  33. * HTTP/1.1 400 Bad Request
  34. * {
  35. * "message": "Missing parameter(s). Required parameters : sceneName, imageQuality."
  36. * }
  37. *
  38. * @apiError (Error 4xx) 400 Invalid query parameter
  39. * @apiErrorExample {json} Invalid query parameter(s)
  40. * HTTP/1.1 400 Bad Request
  41. * {
  42. * "message": "Invalid query parameter(s).",
  43. * "data": [
  44. * "The requested scene name \".//../\" is not valid.",
  45. * "The specified quality is not an integer."
  46. * ]
  47. * }
  48. *
  49. * @apiError (Error 4xx) 404 Quality not found
  50. * @apiErrorExample {json} Quality not found
  51. * HTTP/1.1 404 Not Found
  52. * {
  53. * "message": "The requested quality (9999) was not found for the requested scene (bathroom)."
  54. * }
  55. *
  56. * @apiError (Error 5xx) 500 Can't access the `IMAGES_PATH` directory
  57. * @apiErrorExample {json} Images directory not accessible
  58. * HTTP/1.1 500 Internal Server Error
  59. * {
  60. * "message": "Can't access the \"images\" directory. Check it exists and you have read permission on it"
  61. * }
  62. *
  63. * @apiError (Error 5xx) 500 Failed to parse a file's name
  64. * @apiErrorExample {json} Failed to parse a file's name
  65. * HTTP/1.1 500 Internal Server Error
  66. * {
  67. * "message": "Failed to parse file names in the \"bathroom\"'s scene directory.",
  68. * "data": [
  69. * "The file name does not match convention (scene_000150.ext - /^(.*)?_([0-9]{2,})\\.(.*)$/) : \"bathroom_adz00020.png\".",
  70. * "The file name does not match convention (scene_000150.ext - /^(.*)?_([0-9]{2,})\\.(.*)$/) : \"bathroom_adz00020.png\"."
  71. * ]
  72. * }
  73. *
  74. */
  75. /**
  76. * @typedef {Object} Image
  77. * @property {string} link the link (URL) to an image on the app
  78. * @property {string} path the path to the image in the file system
  79. * @property {string} fileName the name of the image
  80. * @property {string} sceneName the scene of the image
  81. * @property {number} quality the quality of the image
  82. * @property {string} ext the extension of the image
  83. */
  84. /**
  85. * Get the link and path to an image
  86. * @param {string} sceneName the scene to get the image from
  87. * @param {number} qualityInt the requested quality
  88. * @returns {Promise<Image>} the link and path to the image
  89. */
  90. export const getImage = async (sceneName, qualityInt) => {
  91. const sceneData = await getSceneFilesData(sceneName)
  92. // Search an image with the requested quality in the scene
  93. for (const [imageName, imageData] of sceneData.entries())
  94. if (qualityInt === imageData.quality)
  95. return {
  96. link: `${imageServedUrl}/${sceneName}/${imageName}`,
  97. path: path.resolve(imagesPath, sceneName, imageName),
  98. fileName: imageName,
  99. sceneName,
  100. quality: imageData.quality,
  101. ext: imageData.ext
  102. }
  103. // Image not found
  104. throw boom.notFound(`The requested quality (${qualityInt}) was not found for the requested scene (${sceneName}).`)
  105. }
  106. router.get('/', asyncMiddleware(async (req, res) => {
  107. // Check the request contains all the required parameters
  108. checkRequiredParameters(['sceneName', 'imageQuality'], req.query)
  109. const { sceneName, imageQuality } = req.query
  110. let errorList = []
  111. // Check the scene name is valid
  112. try {
  113. checkSceneName(sceneName)
  114. }
  115. catch (err) {
  116. errorList.push(err.message)
  117. }
  118. // Check `imageQuality` is an integer
  119. const qualityInt = parseInt(imageQuality, 10)
  120. if (isNaN(qualityInt)) errorList.push('The specified quality is not an integer.')
  121. // Check there is no errors with parameters
  122. if (errorList.length > 0)
  123. throw boom.badRequest('Invalid query parameter(s).', errorList)
  124. const { link } = await getImage(sceneName, qualityInt)
  125. res.json({ data: link })
  126. }))
  127. export default router