暂存
This commit is contained in:
		
							
								
								
									
										2
									
								
								src/routes/resource/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/routes/resource/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| import './publish.ts'; | ||||
| import './list.ts'; | ||||
							
								
								
									
										1
									
								
								src/routes/resource/lib/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/routes/resource/lib/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './publish-minio.ts'; | ||||
							
								
								
									
										35
									
								
								src/routes/resource/lib/publish-minio.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/routes/resource/lib/publish-minio.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { Resource } from '../models/index.ts'; | ||||
| import { minioClient, bucketName } from '../../../modules/minio.ts'; | ||||
|  | ||||
| type MinioRes = { | ||||
|   etag?: string; // 文件的etag, 用于后续的文件下载 | ||||
|   versionId?: string; | ||||
| }; | ||||
|  | ||||
| type PublishOptions = { | ||||
|   name: string; | ||||
|   version: string; | ||||
|   code: string; | ||||
| }; | ||||
|  | ||||
| export const publishJsCode = async ({ name, version, code }: PublishOptions) => { | ||||
|   // publish to minio | ||||
|   const codeBuffer = Buffer.from(code); | ||||
|   const codePath = `${name}/${version}/index.js`; | ||||
|   try { | ||||
|     const res = await minioClient.putObject(bucketName, codePath, codeBuffer, codeBuffer.length, { | ||||
|       'Content-Type': 'application/javascript', | ||||
|       'Cache-Control': 'max-age=31536000, immutable', | ||||
|     }); | ||||
|     return { | ||||
|       code: 200, | ||||
|       data: { ...res, path: codePath }, | ||||
|     }; | ||||
|   } catch (e) { | ||||
|     console.error('publish error', e.message); | ||||
|     return { | ||||
|       code: 500, | ||||
|       message: e.message, | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										72
									
								
								src/routes/resource/list.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/routes/resource/list.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| import { ResourceData, ResourceModel } from './models/index.ts'; | ||||
| import { app } from '../../app.ts'; | ||||
| import { CustomError } from '@abearxiong/router'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'resource', | ||||
|     key: 'list', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const list = await ResourceModel.findAll({ | ||||
|       order: [['updatedAt', 'DESC']], | ||||
|     }); | ||||
|     ctx.body = list; | ||||
|     return ctx; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'resource', | ||||
|     key: 'get', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const id = ctx.query.id; | ||||
|     if (!id) { | ||||
|       throw new CustomError('id is required'); | ||||
|     } | ||||
|     const rm = await ResourceModel.findByPk(id); | ||||
|     if (!rm) { | ||||
|       throw new CustomError('resource not found'); | ||||
|     } | ||||
|     ctx.body = rm; | ||||
|     return ctx; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ path: 'resource', key: 'update' }) | ||||
|   .define(async (ctx) => { | ||||
|     const { data, id, ...rest } = ctx.query.data; | ||||
|     if (id) { | ||||
|       const resource = await ResourceModel.findByPk(id); | ||||
|       if (resource) { | ||||
|         const newResource = await resource.update({ data, ...rest }); | ||||
|         ctx.body = newResource; | ||||
|       } | ||||
|     } else if (data) { | ||||
|       const resource = await ResourceModel.create({ data, ...rest }); | ||||
|       ctx.body = resource; | ||||
|     } | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'resource', | ||||
|     key: 'delete', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const id = ctx.query.id; | ||||
|     if (!id) { | ||||
|       throw new CustomError('id is required'); | ||||
|     } | ||||
|     const resource = await ResourceModel.findByPk(id); | ||||
|     if (!resource) { | ||||
|       throw new CustomError('resource not found'); | ||||
|     } | ||||
|     await resource.destroy(); | ||||
|     ctx.body = 'success'; | ||||
|   }) | ||||
|   .addTo(app); | ||||
							
								
								
									
										87
									
								
								src/routes/resource/models/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/routes/resource/models/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| import { sequelize } from '../../../modules/sequelize.ts'; | ||||
| import { DataTypes, Model } from 'sequelize'; | ||||
|  | ||||
| type FileUrlList = { | ||||
|   path: string; | ||||
|   etag: string; | ||||
|   versionId: string; | ||||
| }; | ||||
| export interface ResourceData { | ||||
|   list: FileUrlList[]; | ||||
|   lastestVersion: string; | ||||
|   updatedAt: string; | ||||
|   [key: string]: any; | ||||
| } | ||||
| export const defaultData: ResourceData = { | ||||
|   list: [], | ||||
|   lastestVersion: '0.0.0', | ||||
|   updatedAt: '', | ||||
| }; | ||||
| export type Resource = { | ||||
|   id?: string; | ||||
|   name?: string; | ||||
|   description?: string; | ||||
|   source?: string; | ||||
|   sourceId?: string; | ||||
|   data?: ResourceData; | ||||
|   version?: string; | ||||
|   uid?: string; | ||||
| }; | ||||
|  | ||||
| export class ResourceModel extends Model { | ||||
|   declare id: string; | ||||
|   declare name: string; | ||||
|   declare description: string; | ||||
|   declare source: string; | ||||
|   declare sourceId: string; | ||||
|   declare data: ResourceData; | ||||
|   declare version: string; | ||||
|   declare uid: string; | ||||
| } | ||||
|  | ||||
| ResourceModel.init( | ||||
|   { | ||||
|     id: { | ||||
|       type: DataTypes.UUID, | ||||
|       primaryKey: true, | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       comment: 'id', | ||||
|     }, | ||||
|     name: { | ||||
|       type: DataTypes.STRING, // 第一次创建之后就不能修改了,因为这个是用来做唯一标识的 | ||||
|       defaultValue: '', | ||||
|     }, | ||||
|     description: { | ||||
|       type: DataTypes.TEXT, | ||||
|       defaultValue: '', | ||||
|     }, | ||||
|     source: { | ||||
|       type: DataTypes.STRING, | ||||
|       defaultValue: '', | ||||
|     }, | ||||
|     sourceId: { | ||||
|       type: DataTypes.STRING, | ||||
|       defaultValue: '', | ||||
|     }, | ||||
|     version: { | ||||
|       type: DataTypes.STRING, | ||||
|       defaultValue: '0.0.0', | ||||
|     }, | ||||
|     data: { | ||||
|       type: DataTypes.JSON, | ||||
|       defaultValue: {}, | ||||
|     }, | ||||
|     uid: { | ||||
|       type: DataTypes.UUID, | ||||
|       allowNull: true, | ||||
|     }, | ||||
|   }, | ||||
|   { | ||||
|     sequelize, | ||||
|     tableName: 'kv_resource', | ||||
|   }, | ||||
| ); | ||||
|  | ||||
| ResourceModel.sync({ alter: true, logging: false }).catch((e) => { | ||||
|   console.error('ResourceModel sync', e); | ||||
| }); | ||||
							
								
								
									
										69
									
								
								src/routes/resource/publish.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/routes/resource/publish.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| import { defaultData, Resource, ResourceModel } from './models/index.ts'; | ||||
| import { ContainerModel } from './../container/models/index.ts'; | ||||
|  | ||||
| import { app } from '../../app.ts'; | ||||
| import { Op } from 'sequelize'; | ||||
| import { publishJsCode } from './lib/publish-minio.ts'; | ||||
| import { CustomError } from '@abearxiong/router'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'resource', | ||||
|     key: 'publishContainer', | ||||
|     idUsePath: true, | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const container = ctx.state.container as ContainerModel; | ||||
|     const publish = container.publish; | ||||
|     const code = container.code; | ||||
|     let { name, rid, description, version = '0.0.1' } = publish; | ||||
|     const where = []; | ||||
|     if (rid) { | ||||
|       where.push({ id: rid }); | ||||
|     } | ||||
|     if (name) { | ||||
|       where.push({ name }); | ||||
|     } | ||||
|     let resource = await ResourceModel.findOne({ where: { [Op.or]: where } }); | ||||
|     let isCreate = false; | ||||
|     if (!resource) { | ||||
|       isCreate = true; | ||||
|       resource = await ResourceModel.create({ | ||||
|         name, | ||||
|         description, | ||||
|         version, | ||||
|         source: 'container', | ||||
|         sourceId: container.id, | ||||
|         data: { | ||||
|           ...defaultData, | ||||
|           updatedAt: new Date().toISOString(), | ||||
|         }, | ||||
|       }); | ||||
|     } | ||||
|     publish.rid = publish.rid || resource.id; | ||||
|     // TODO: check version | ||||
|     const res = await publishJsCode({ name, version, code }); | ||||
|     if (res.code === 200) { | ||||
|       await container.update({ publish }); | ||||
|       const { etag, versionId, path } = res.data; | ||||
|       resource.version = version; | ||||
|       const newData = { | ||||
|         list: [], | ||||
|         ...resource.data, | ||||
|       }; | ||||
|       newData.list.push({ | ||||
|         etag, | ||||
|         versionId, | ||||
|         path, | ||||
|       }); | ||||
|       newData.lastestVersion = version; | ||||
|       newData.updatedAt = new Date().toISOString(); | ||||
|       resource.data = newData; | ||||
|       await resource.save(); | ||||
|       ctx.body = { resource, container, resourceIsNew: isCreate }; | ||||
|     } else { | ||||
|       throw new CustomError(res.message); | ||||
|     } | ||||
|     // await container.update({ publish }); | ||||
|   }) | ||||
|   .addTo(app); | ||||
		Reference in New Issue
	
	Block a user