This commit is contained in:
2024-09-20 22:04:27 +08:00
parent e3991379df
commit a8f80abc88
15 changed files with 892 additions and 66 deletions

View File

@@ -0,0 +1,2 @@
import './publish.ts';
import './list.ts';

View File

@@ -0,0 +1 @@
export * from './publish-minio.ts';

View 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,
};
}
};

View 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);

View 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);
});

View 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);