config
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { IncomingForm } from 'formidable';
|
||||
import { checkAuth } from '../middleware/auth.ts';
|
||||
import { router } from '../router.ts';
|
||||
import { router, clients, writeEvents } from '../router.ts';
|
||||
import { error } from '../middleware/auth.ts';
|
||||
import fs from 'fs';
|
||||
import { clients } from '../upload.ts';
|
||||
import { useFileStore } from '@kevisual/use-config/file-store';
|
||||
import { app, minioClient } from '@/app.ts';
|
||||
import { bucketName } from '@/modules/minio.ts';
|
||||
@@ -29,7 +28,6 @@ router.post('/api/micro-app/upload', async (req, res) => {
|
||||
keepExtensions: true, // 保留文件
|
||||
hashAlgorithm: 'md5', // 文件哈希算法
|
||||
});
|
||||
const taskId = req.headers['task-id'] as string;
|
||||
form.on('progress', (bytesReceived, bytesExpected) => {
|
||||
const progress = (bytesReceived / bytesExpected) * 100;
|
||||
console.log(`Upload progress: ${progress.toFixed(2)}%`);
|
||||
@@ -37,7 +35,7 @@ router.post('/api/micro-app/upload', async (req, res) => {
|
||||
progress: progress.toFixed(2),
|
||||
message: `Upload progress: ${progress.toFixed(2)}%`,
|
||||
};
|
||||
clients.get(taskId)?.client?.write?.(`${JSON.stringify(data)}\n`);
|
||||
writeEvents(req, data);
|
||||
});
|
||||
// 解析上传的文件
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
|
||||
22
src/routes-simple/event.ts
Normal file
22
src/routes-simple/event.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { router, error, checkAuth, clients, getTaskId } from './router.ts';
|
||||
|
||||
router.get('/api/events', async (req, res) => {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
Connection: 'keep-alive',
|
||||
});
|
||||
const tokenUser = await checkAuth(req, res);
|
||||
if (!tokenUser) return;
|
||||
const taskId = getTaskId(req);
|
||||
if (!taskId) {
|
||||
res.end(error('task-id is required'));
|
||||
return;
|
||||
}
|
||||
// 将客户端连接推送到 clients 数组
|
||||
clients.set(taskId, { client: res, tokenUser });
|
||||
// 移除客户端连接
|
||||
req.on('close', () => {
|
||||
clients.delete(taskId);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +1,25 @@
|
||||
import { User } from '@/models/user.ts';
|
||||
import http from 'http';
|
||||
|
||||
import cookie from 'cookie';
|
||||
export const error = (msg: string, code = 500) => {
|
||||
return JSON.stringify({ code, message: msg });
|
||||
};
|
||||
export const checkAuth = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
let token = '';
|
||||
const authroization = req.headers?.['authorization'] as string;
|
||||
let token = (req.headers?.['authorization'] as string) || '';
|
||||
const url = new URL(req.url || '', 'http://localhost');
|
||||
const resNoPermission = () => {
|
||||
res.statusCode = 401;
|
||||
res.end(error('Invalid authorization'));
|
||||
return { tokenUser: null, token: null };
|
||||
};
|
||||
if (authroization) {
|
||||
// return resNoPermission();
|
||||
token = authroization.split(' ')[1];
|
||||
} else if (url.searchParams.get('token')) {
|
||||
if (!token) {
|
||||
token = url.searchParams.get('token') || '';
|
||||
} else {
|
||||
}
|
||||
if (!token) {
|
||||
const parsedCookies = cookie.parse(req.headers.cookie || '');
|
||||
token = parsedCookies.token || '';
|
||||
}
|
||||
if (!token) {
|
||||
return resNoPermission();
|
||||
}
|
||||
let tokenUser;
|
||||
|
||||
@@ -1,3 +1,31 @@
|
||||
import { SimpleRouter } from '@kevisual/router/simple';
|
||||
import { router } from '@/app.ts';
|
||||
import http from 'http';
|
||||
import { useContextKey } from '@kevisual/use-config/context';
|
||||
export const router = useContextKey('router', () => new SimpleRouter());
|
||||
import { checkAuth, error } from './middleware/auth.ts';
|
||||
export { router, checkAuth, error };
|
||||
|
||||
/**
|
||||
* 事件客户端
|
||||
*/
|
||||
const eventClientsInit = () => {
|
||||
const clients = new Map<string, { client?: http.ServerResponse; [key: string]: any }>();
|
||||
return clients;
|
||||
};
|
||||
export const clients = useContextKey('event-clients', () => eventClientsInit());
|
||||
/**
|
||||
* 获取 task-id
|
||||
* @param req
|
||||
* @returns
|
||||
*/
|
||||
export const getTaskId = (req: http.IncomingMessage) => {
|
||||
return req.headers['task-id'] as string;
|
||||
};
|
||||
/**
|
||||
* 写入事件
|
||||
* @param req
|
||||
* @param data
|
||||
*/
|
||||
export const writeEvents = (req: http.IncomingMessage, data: any) => {
|
||||
const taskId = getTaskId(req);
|
||||
taskId && clients.get(taskId)?.client?.write?.(`${JSON.stringify(data)}\n`);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import { bucketName } from '@/modules/minio.ts';
|
||||
import { getContentType } from '@/utils/get-content-type.ts';
|
||||
import { User } from '@/models/user.ts';
|
||||
import { getContainerById } from '@/routes/container/module/get-container-file.ts';
|
||||
import { router } from './router.ts';
|
||||
import { router, error, checkAuth, clients, writeEvents } from './router.ts';
|
||||
import './index.ts';
|
||||
|
||||
const filePath = useFileStore('upload', { needExists: true });
|
||||
@@ -21,29 +21,6 @@ const cacheFilePath = useFileStore('cache-file', { needExists: true });
|
||||
// -F "description=This is a test upload" \
|
||||
// -F "username=testuser"
|
||||
|
||||
export const clients = new Map<string, { client?: http.ServerResponse; [key: string]: any }>();
|
||||
|
||||
const error = (msg: string, code = 500) => {
|
||||
return JSON.stringify({ code, message: msg });
|
||||
};
|
||||
const checkAuth = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
const authroization = req.headers?.['authorization'] as string;
|
||||
if (!authroization) {
|
||||
res.statusCode = 401;
|
||||
res.end(error('Invalid authorization'));
|
||||
return { tokenUser: null, token: null };
|
||||
}
|
||||
const token = authroization.split(' ')[1];
|
||||
let tokenUser;
|
||||
try {
|
||||
tokenUser = await User.verifyToken(token);
|
||||
} catch (e) {
|
||||
res.statusCode = 401;
|
||||
res.end(error('Invalid token'));
|
||||
return { tokenUser: null, token: null };
|
||||
}
|
||||
return { tokenUser, token };
|
||||
};
|
||||
router.get('/api/app/upload', async (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Upload API is ready');
|
||||
@@ -59,6 +36,16 @@ router.post('/api/upload', async (req, res) => {
|
||||
uploadDir: filePath, // 上传文件存储目录
|
||||
allowEmptyFiles: true, // 允许空文件
|
||||
});
|
||||
form.on('progress', (bytesReceived, bytesExpected) => {
|
||||
const progress = (bytesReceived / bytesExpected) * 100;
|
||||
console.log(`Upload progress: ${progress.toFixed(2)}%`);
|
||||
const data = {
|
||||
progress: progress.toFixed(2),
|
||||
message: `Upload progress: ${progress.toFixed(2)}%`,
|
||||
};
|
||||
writeEvents(req, data);
|
||||
});
|
||||
|
||||
// 解析上传的文件
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
@@ -101,7 +88,6 @@ router.post('/api/app/upload', async (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
const { tokenUser, token } = await checkAuth(req, res);
|
||||
if (!tokenUser) return;
|
||||
//
|
||||
// 使用 formidable 解析 multipart/form-data
|
||||
const form = new IncomingForm({
|
||||
multiples: true, // 支持多文件上传
|
||||
@@ -119,8 +105,7 @@ router.post('/api/app/upload', async (req, res) => {
|
||||
progress: progress.toFixed(2),
|
||||
message: `Upload progress: ${progress.toFixed(2)}%`,
|
||||
};
|
||||
// 向所有连接的客户端推送进度信息
|
||||
clients.forEach((client) => client.write(`${JSON.stringify(data)}\n`));
|
||||
writeEvents(req, data);
|
||||
});
|
||||
// 解析上传的文件
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
@@ -225,24 +210,7 @@ router.post('/api/app/upload', async (req, res) => {
|
||||
res.end(JSON.stringify(data));
|
||||
});
|
||||
});
|
||||
router.get('/api/events', async (req, res) => {
|
||||
if (req.url === '/api/events') {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
Connection: 'keep-alive',
|
||||
});
|
||||
const tokenUser = await checkAuth(req, res);
|
||||
if (!tokenUser) return;
|
||||
const taskId = req.headers['task-id'] as string;
|
||||
// 将客户端连接推送到 clients 数组
|
||||
clients.set(taskId, { client: res, tokenUser });
|
||||
// 移除客户端连接
|
||||
req.on('close', () => {
|
||||
clients.delete(taskId);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/api/container/file/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
if (!id) {
|
||||
|
||||
Reference in New Issue
Block a user