post.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
  2. import { FileService } from '@/server/modules/files/file.service';
  3. import { ErrorSchema } from '@/server/utils/errorHandler';
  4. import { AppDataSource } from '@/server/data-source';
  5. import { AuthContext } from '@/server/types/context';
  6. import { authMiddleware } from '@/server/middleware/auth.middleware';
  7. // 完成分片上传请求Schema
  8. const CompleteMultipartUploadDto = z.object({
  9. uploadId: z.string().openapi({
  10. description: '分片上传ID',
  11. example: '123e4567-e89b-12d3-a456-426614174000'
  12. }),
  13. bucket: z.string().openapi({
  14. description: '存储桶名称',
  15. example: 'my-bucket'
  16. }),
  17. key: z.string().openapi({
  18. description: '文件键名',
  19. example: 'documents/report.pdf'
  20. }),
  21. parts: z.array(
  22. z.object({
  23. partNumber: z.coerce.number().int().positive().openapi({
  24. description: '分片序号',
  25. example: 1
  26. }),
  27. etag: z.string().openapi({
  28. description: '分片ETag值',
  29. example: 'd41d8cd98f00b204e9800998ecf8427e'
  30. })
  31. })
  32. ).openapi({
  33. description: '分片信息列表',
  34. example: [
  35. { partNumber: 1, etag: 'd41d8cd98f00b204e9800998ecf8427e' },
  36. { partNumber: 2, etag: '5f4dcc3b5aa765d61d8327deb882cf99' }
  37. ]
  38. })
  39. });
  40. // 完成分片上传响应Schema
  41. const CompleteMultipartUploadResponse = z.object({
  42. fileId: z.string().openapi({
  43. description: '文件ID',
  44. example: 'file_123456'
  45. }),
  46. url: z.string().openapi({
  47. description: '文件访问URL',
  48. example: 'https://minio.example.com/my-bucket/documents/report.pdf'
  49. }),
  50. host: z.string().openapi({
  51. description: 'MinIO主机地址',
  52. example: 'minio.example.com'
  53. }),
  54. bucket: z.string().openapi({
  55. description: '存储桶名称',
  56. example: 'my-bucket'
  57. }),
  58. key: z.string().openapi({
  59. description: '文件键名',
  60. example: 'documents/report.pdf'
  61. })
  62. });
  63. // 创建完成分片上传路由定义
  64. const completeMultipartUploadRoute = createRoute({
  65. method: 'post',
  66. path: '/',
  67. middleware: [authMiddleware],
  68. request: {
  69. body: {
  70. content: {
  71. 'application/json': { schema: CompleteMultipartUploadDto }
  72. }
  73. }
  74. },
  75. responses: {
  76. 200: {
  77. description: '完成分片上传成功',
  78. content: {
  79. 'application/json': { schema: CompleteMultipartUploadResponse }
  80. }
  81. },
  82. 400: {
  83. description: '请求参数错误',
  84. content: { 'application/json': { schema: ErrorSchema } }
  85. },
  86. 500: {
  87. description: '服务器错误',
  88. content: { 'application/json': { schema: ErrorSchema } }
  89. }
  90. }
  91. });
  92. // 初始化FileService
  93. const fileService = new FileService(AppDataSource);
  94. // 创建路由实例并实现处理逻辑
  95. const app = new OpenAPIHono<AuthContext>().openapi(completeMultipartUploadRoute, async (c) => {
  96. try {
  97. const data = await c.req.json();
  98. const result = await fileService.completeMultipartUpload(data);
  99. // 构建完整的响应包含host和bucket信息
  100. const response = {
  101. ...result,
  102. host: `${process.env.MINIO_USE_SSL ? 'https' : 'http'}://${process.env.MINIO_ENDPOINT}:${process.env.MINIO_PORT}`,
  103. bucket: data.bucket
  104. };
  105. return c.json(response, 200);
  106. } catch (error) {
  107. const message = error instanceof Error ? error.message : '完成分片上传失败';
  108. return c.json({ code: 500, message }, 500);
  109. }
  110. });
  111. export default app;