feat: 下载page到本地

This commit is contained in:
2024-10-08 17:10:32 +08:00
parent 54e3ccb3ff
commit 8cdd54af04
9 changed files with 361 additions and 8 deletions

View File

@@ -9,10 +9,13 @@ app
.route({
path: 'chat-prompt',
key: 'list',
// middleware: ['auth'],
})
.define(async (ctx) => {
const chatPrompt = await ChatPrompt.findAll({
order: [['updatedAt', 'DESC']],
// 列出被删除的
// paranoid: false,
});
ctx.body = chatPrompt;
})
@@ -78,6 +81,7 @@ app
required: true,
},
},
middleware: ['auth'],
})
.define(async (ctx) => {
const id = ctx.query.id;
@@ -93,6 +97,7 @@ app
.route({
path: 'chat-prompt',
key: 'getByKey',
middleware: ['auth'],
})
.define(async (ctx) => {
const { key } = ctx.query.data || {};

View File

@@ -9,6 +9,9 @@ import { getHTML, getDataJs } from './file-template.ts';
import { minioClient } from '@/app.ts';
import { bucketName } from '@/modules/minio.ts';
import { getContentType } from '@/utils/get-content-type.ts';
import archiver from 'archiver';
import { CustomError } from '@abearxiong/router';
export const cacheFile = useFileStore('cache-file', {
needExists: true,
});
@@ -72,3 +75,80 @@ export const uploadMinio = async ({ tokenUser, key, version, path, filePath }) =
fs.unlinkSync(filePath); // 删除临时文件
return minioPath;
};
export const uploadMinioTemp = async ({ tokenUser, filePath, path }) => {
const minioPath = `${tokenUser.username}/temp/${path}`;
const isHTML = filePath.endsWith('.html');
await minioClient.fPutObject(bucketName, minioPath, filePath, {
'Content-Type': getContentType(filePath),
'app-source': 'user-app',
'Cache-Control': isHTML ? 'no-cache' : 'max-age=31536000, immutable', // 缓存一年
});
fs.unlinkSync(filePath); // 删除临时文件
return minioPath;
};
export const getZip = async (page: PageModel, opts: { tokenUser: any }) => {
const _result = await getDeck(page);
const result = getContainerData(_result);
const html = getHTML({ rootId: page.id, title: page?.publish?.key });
const dataJs = getDataJs(result);
const zip = archiver('zip', {
zlib: { level: 9 },
});
// 创建 zip 文件的输出流
const zipCache = path.join(cacheFile, `${page.id}.zip`);
if (checkFileExistsSync(zipCache)) {
throw new CustomError('page is on uploading');
}
return await new Promise((resolve, reject) => {
const output = fs.createWriteStream(zipCache);
// 监听事件
output.on('close', async () => {
console.log(`Zip file has been created successfully. Total size: ${zip.pointer()} bytes.`);
let time = (new Date().getTime() / 1000).toFixed(0);
const name = page.title || page.id;
const minioPath = await uploadMinioTemp({ ...opts, filePath: zipCache, path: `${name + '-' + time}.zip` });
resolve(minioPath);
});
output.on('end', () => {
console.log('Data has been drained.'); // 数据已被耗尽
throw new CustomError('Data has been drained.');
});
zip.on('warning', (err) => {
if (err.code === 'ENOENT') {
console.warn('File not found:', err);
} else {
throw err;
}
});
zip.on('error', (err) => {
throw err;
});
// 通过管道将 zip 数据流输出到指定文件
zip.pipe(output);
// 添加 HTML 字符串作为文件到 zip 中
zip.append(html, { name: 'index.html' });
// 添加 JavaScript 字符串作为文件到 zip 中
zip.append(dataJs, { name: 'data.js' });
// 可以继续添加更多内容,文件或目录等
// zip.append('Another content', { name: 'other.txt' });
// 结束归档(必须调用,否则 zip 文件无法完成)
zip.finalize();
});
};
export const checkFileExistsSync = (filePath: string) => {
try {
// 使用 F_OK 检查文件或目录是否存在
fs.accessSync(filePath, fs.constants.F_OK);
return true;
} catch (err) {
return false;
}
};

View File

@@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid';
import { ContainerModel } from '../container/models/index.ts';
import { Op } from 'sequelize';
import { AppListModel, AppModel } from '../app-manager/index.ts';
import { cachePage } from './module/cache-file.ts';
import { cachePage, getZip } from './module/cache-file.ts';
import _ from 'lodash';
import semver from 'semver';
@@ -67,3 +67,26 @@ app
}
})
.addTo(app);
app
.route({
path: 'page',
key: 'download',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id } = ctx.query;
const page = await PageModel.findByPk(id);
if (!page) {
throw new CustomError('page not found');
}
try {
const files = await getZip(page, { tokenUser });
ctx.body = files;
} catch (e) {
console.log('error', e);
throw new CustomError(e.message || 'download error');
}
})
.addTo(app);