uploadx.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import express, { Request, Response, NextFunction, RequestHandler } from 'express'
  2. import { buildLogger } from '@server/helpers/logger.js'
  3. import { getResumableUploadPath } from '@server/helpers/upload.js'
  4. import { CONFIG } from '@server/initializers/config.js'
  5. import { FileQuery, LogLevel, Uploadx, Metadata as UploadXMetadata } from '@uploadx/core'
  6. import { extname } from 'path'
  7. import { authenticate } from '@server/middlewares/auth.js'
  8. import { resumableInitValidator } from '@server/middlewares/validators/resumable-upload.js'
  9. const logger = buildLogger('uploadx')
  10. export const uploadx = new Uploadx({
  11. directory: getResumableUploadPath(),
  12. expiration: { maxAge: undefined, rolling: true },
  13. // Could be big with thumbnails/previews
  14. maxMetadataSize: '10MB',
  15. logger: {
  16. logLevel: CONFIG.LOG.LEVEL as LogLevel,
  17. debug: logger.debug.bind(logger),
  18. info: logger.info.bind(logger),
  19. warn: logger.warn.bind(logger),
  20. error: logger.error.bind(logger)
  21. },
  22. userIdentifier: (_, res: express.Response) => {
  23. if (!res.locals.oauth) return undefined
  24. return res.locals.oauth.token.user.id + ''
  25. },
  26. filename: file => `${file.userId}-${file.id}${extname(file.metadata.filename)}`
  27. })
  28. export function safeUploadXCleanup (file: FileQuery) {
  29. uploadx.storage.delete(file)
  30. .catch(err => logger.error('Cannot delete the file %s', file.name, { err }))
  31. }
  32. export function buildUploadXFile <T extends UploadXMetadata> (reqBody: T) {
  33. return {
  34. ...reqBody,
  35. path: getResumableUploadPath(reqBody.name),
  36. filename: reqBody.metadata.filename
  37. }
  38. }
  39. export function setupUploadResumableRoutes (options: {
  40. router: express.Router
  41. routePath: string
  42. uploadInitBeforeMiddlewares?: RequestHandler[]
  43. uploadInitAfterMiddlewares?: RequestHandler[]
  44. uploadedMiddlewares?: ((req: Request<any>, res: Response, next: NextFunction) => void)[]
  45. uploadedController: (req: Request<any>, res: Response, next: NextFunction) => void
  46. uploadDeleteMiddlewares?: RequestHandler[]
  47. }) {
  48. const {
  49. router,
  50. routePath,
  51. uploadedMiddlewares = [],
  52. uploadedController,
  53. uploadInitBeforeMiddlewares = [],
  54. uploadInitAfterMiddlewares = [],
  55. uploadDeleteMiddlewares = []
  56. } = options
  57. router.post(routePath,
  58. authenticate,
  59. ...uploadInitBeforeMiddlewares,
  60. resumableInitValidator,
  61. ...uploadInitAfterMiddlewares,
  62. (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitly tell to uploadx it's the end
  63. )
  64. router.delete(routePath,
  65. authenticate,
  66. ...uploadDeleteMiddlewares,
  67. (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitly tell to uploadx it's the end
  68. )
  69. router.put(routePath,
  70. authenticate,
  71. uploadx.upload, // uploadx doesn't next() before the file upload completes
  72. ...uploadedMiddlewares,
  73. uploadedController
  74. )
  75. }