bun 多文件上传会有问题
This commit is contained in:
parent
cdbebe92d0
commit
4aec2bc231
15
package.json
15
package.json
@ -25,7 +25,8 @@
|
|||||||
"bun.config.mjs"
|
"bun.config.mjs"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run src/run.ts ",
|
"dev": "bun src/run.ts ",
|
||||||
|
"dev:tsx": "tsx src/run.ts ",
|
||||||
"build": "rimraf dist && bun run bun.config.mjs",
|
"build": "rimraf dist && bun run bun.config.mjs",
|
||||||
"postbuild": "cd assistant && pnpm build",
|
"postbuild": "cd assistant && pnpm build",
|
||||||
"dts": "dts-bundle-generator --external-inlines=@types/jsonwebtoken src/index.ts -o dist/index.d.ts ",
|
"dts": "dts-bundle-generator --external-inlines=@types/jsonwebtoken src/index.ts -o dist/index.d.ts ",
|
||||||
@ -43,23 +44,23 @@
|
|||||||
"@kevisual/load": "^0.0.6",
|
"@kevisual/load": "^0.0.6",
|
||||||
"@kevisual/query": "0.0.17",
|
"@kevisual/query": "0.0.17",
|
||||||
"@kevisual/query-login": "0.0.5",
|
"@kevisual/query-login": "0.0.5",
|
||||||
"@types/bun": "^1.2.10",
|
"@types/bun": "^1.2.13",
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/jsonwebtoken": "^9.0.9",
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.15.17",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"commander": "^13.1.0",
|
"commander": "^13.1.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"filesize": "^10.1.6",
|
"filesize": "^10.1.6",
|
||||||
"form-data": "^4.0.2",
|
"form-data": "^4.0.2",
|
||||||
"ignore": "^7.0.3",
|
"ignore": "^7.0.4",
|
||||||
"inquirer": "^12.5.2",
|
"inquirer": "^12.6.1",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"rollup": "^4.40.0",
|
"rollup": "^4.40.2",
|
||||||
"rollup-plugin-dts": "^6.2.1",
|
"rollup-plugin-dts": "^6.2.1",
|
||||||
"tar": "^7.4.3",
|
"tar": "^7.4.3",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.0.0"
|
"node": ">=22.0.0"
|
||||||
|
962
pnpm-lock.yaml
generated
962
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
|||||||
import { chalk } from '@/module/chalk.ts';
|
import { chalk } from '@/module/chalk.ts';
|
||||||
import { program, Command } from '../../../program.ts';
|
import { program, Command } from '../../../program.ts';
|
||||||
import { queryApp } from '../../../query/app-manager/query-app.ts';
|
import { queryApp } from '../../../query/app-manager/query-app.ts';
|
||||||
import { checkAppDir, installApp, uninstallApp } from '@/module/download/install.ts';
|
import { checkAppDir, installApp, uninstallApp, fetchLink } from '@/module/download/install.ts';
|
||||||
import { fileIsExist } from '@/uitls/file.ts';
|
import { fileIsExist } from '@/uitls/file.ts';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { getConfig } from '@/module/get-config.ts';
|
import { getConfig } from '@/module/get-config.ts';
|
||||||
@ -156,3 +156,20 @@ const uninstallAppCommand = new Command('uninstall')
|
|||||||
|
|
||||||
appCommand.addCommand(downloadAppCommand);
|
appCommand.addCommand(downloadAppCommand);
|
||||||
appCommand.addCommand(uninstallAppCommand);
|
appCommand.addCommand(uninstallAppCommand);
|
||||||
|
|
||||||
|
const link = new Command('link')
|
||||||
|
.argument('url')
|
||||||
|
.option('-o --output <output>', '输出目录')
|
||||||
|
.action(async (url, options) => {
|
||||||
|
const output = options.output || '';
|
||||||
|
const { content, filename } = await fetchLink(url, { returnContent: true });
|
||||||
|
if (output) {
|
||||||
|
const checkOutput = fileIsExist(output);
|
||||||
|
if (!checkOutput) {
|
||||||
|
fs.mkdirSync(output, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.writeFileSync(path.join(output, filename), content);
|
||||||
|
});
|
||||||
|
|
||||||
|
appCommand.addCommand(link);
|
||||||
|
@ -9,7 +9,9 @@ import inquirer from 'inquirer';
|
|||||||
import { packLib, unpackLib } from './publish.ts';
|
import { packLib, unpackLib } from './publish.ts';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { installDeps } from '@/uitls/npm.ts';
|
import { installDeps } from '@/uitls/npm.ts';
|
||||||
import { MD5 } from 'crypto-js';
|
import cryptojs from 'crypto-js';
|
||||||
|
import { upload } from '@/module/download/upload.ts';
|
||||||
|
const MD5 = cryptojs.MD5;
|
||||||
/**
|
/**
|
||||||
* 获取package.json 中的 basename, version, user, appKey
|
* 获取package.json 中的 basename, version, user, appKey
|
||||||
* @returns
|
* @returns
|
||||||
@ -209,8 +211,10 @@ const uploadFiles = async (files: string[], directory: string, opts: UploadFileO
|
|||||||
console.log('文件已经上传过了', file);
|
console.log('文件已经上传过了', file);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const filename = path.basename(filePath);
|
||||||
|
console.log('upload file', file, filename);
|
||||||
form.append('file', fs.createReadStream(filePath), {
|
form.append('file', fs.createReadStream(filePath), {
|
||||||
filename: file,
|
filename: filename,
|
||||||
filepath: file,
|
filepath: file,
|
||||||
});
|
});
|
||||||
needUpload = true;
|
needUpload = true;
|
||||||
@ -221,50 +225,12 @@ const uploadFiles = async (files: string[], directory: string, opts: UploadFileO
|
|||||||
code: 200,
|
code: 200,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const _baseURL = getBaseURL();
|
||||||
return new Promise(async (resolve) => {
|
const url = new URL('/api/s1/resources/upload', _baseURL);
|
||||||
const _baseURL = getBaseURL();
|
if (opts.noCheckAppFiles) {
|
||||||
const url = new URL('/api/s1/resources/upload', _baseURL);
|
url.searchParams.append('noCheckAppFiles', 'true');
|
||||||
const searchParams = url.searchParams;
|
}
|
||||||
if (opts.noCheckAppFiles) {
|
return upload({ url: url, form: form, token: token });
|
||||||
searchParams.append('noCheckAppFiles', 'true');
|
|
||||||
}
|
|
||||||
console.log('upload url', url.hostname, url.protocol, url.port);
|
|
||||||
const pathname = url.href.toString().replace(_baseURL.toString(), '');
|
|
||||||
form.submit(
|
|
||||||
{
|
|
||||||
path: pathname,
|
|
||||||
host: url.hostname,
|
|
||||||
protocol: url.protocol as any,
|
|
||||||
port: url.port,
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: 'Bearer ' + token,
|
|
||||||
...form.getHeaders(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
(err, res) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error uploading file:', err.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 处理服务器响应
|
|
||||||
let body = '';
|
|
||||||
res.on('data', (chunk) => {
|
|
||||||
body += chunk;
|
|
||||||
});
|
|
||||||
|
|
||||||
res.on('end', () => {
|
|
||||||
try {
|
|
||||||
const res = JSON.parse(body);
|
|
||||||
resolve(res);
|
|
||||||
} catch (e) {
|
|
||||||
resolve({ code: 500, message: body });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
app.addCommand(command);
|
app.addCommand(command);
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { program as app, Command } from '@/program.ts';
|
import { program as app, Command } from '@/program.ts';
|
||||||
|
|
||||||
const command = new Command('sync').description('同步项目').action(() => {
|
const command = new Command('sync')
|
||||||
console.log('同步项目');
|
.option('-d --dir <dir>')
|
||||||
});
|
.description('同步项目')
|
||||||
|
.action(() => {
|
||||||
|
console.log('同步项目');
|
||||||
|
});
|
||||||
const syncUpload = new Command('upload').description('上传项目').action(() => {
|
const syncUpload = new Command('upload').description('上传项目').action(() => {
|
||||||
console.log('上传项目');
|
console.log('上传项目');
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { storage } from '../query.ts';
|
import { storage, baseURL } from '../query.ts';
|
||||||
import { chalk } from '../chalk.ts';
|
import { chalk } from '../chalk.ts';
|
||||||
|
|
||||||
type DownloadTask = {
|
type DownloadTask = {
|
||||||
@ -20,6 +20,40 @@ export type Package = {
|
|||||||
key?: string;
|
key?: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
type Options = {
|
||||||
|
check?: boolean;
|
||||||
|
returnContent?: boolean;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
export const fetchLink = async (url: string, opts?: Options) => {
|
||||||
|
const token = process.env.KEVISUAL_TOKEN || storage.getItem('token');
|
||||||
|
const fetchURL = new URL(url);
|
||||||
|
const check = opts?.check ?? false;
|
||||||
|
if (check) {
|
||||||
|
if (!url.startsWith(baseURL)) {
|
||||||
|
throw new Error('url must start with ' + baseURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token) {
|
||||||
|
fetchURL.searchParams.set('token', token);
|
||||||
|
}
|
||||||
|
fetchURL.searchParams.set('download', 'true');
|
||||||
|
const res = await fetch(fetchURL.toString());
|
||||||
|
const blob = await res.blob();
|
||||||
|
const type = blob.type;
|
||||||
|
let content: Buffer | undefined;
|
||||||
|
if (opts?.returnContent) {
|
||||||
|
content = Buffer.from(await blob.arrayBuffer());
|
||||||
|
}
|
||||||
|
const pathname = fetchURL.pathname;
|
||||||
|
const filename = pathname.split('/').pop();
|
||||||
|
return {
|
||||||
|
filename,
|
||||||
|
blob,
|
||||||
|
type,
|
||||||
|
content,
|
||||||
|
};
|
||||||
|
};
|
||||||
type InstallAppOpts = {
|
type InstallAppOpts = {
|
||||||
appDir?: string;
|
appDir?: string;
|
||||||
kevisualUrl?: string;
|
kevisualUrl?: string;
|
||||||
@ -65,20 +99,12 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => {
|
|||||||
fs.mkdirSync(dir, { recursive: true });
|
fs.mkdirSync(dir, { recursive: true });
|
||||||
}
|
}
|
||||||
console.log('downloadUrwl', downloadUrl);
|
console.log('downloadUrwl', downloadUrl);
|
||||||
const token = process.env.KEVISUAL_TOKEN || storage.getItem('token');
|
const { blob, type } = await fetchLink(downloadUrl);
|
||||||
const fetchURL = new URL(downloadUrl);
|
|
||||||
if (token) {
|
|
||||||
fetchURL.searchParams.set('token', token);
|
|
||||||
}
|
|
||||||
fetchURL.searchParams.set('download', 'true');
|
|
||||||
const res = await fetch(fetchURL.toString());
|
|
||||||
const blob = await res.blob();
|
|
||||||
const type = blob.type;
|
|
||||||
if (type.includes('text/html')) {
|
if (type.includes('text/html')) {
|
||||||
const html = await blob.text();
|
const html = await blob.text();
|
||||||
if (html === 'fetchRes is error') {
|
if (html === 'fetchRes is error') {
|
||||||
console.log(chalk.red('fetchRes is error'));
|
console.log(chalk.red('fetchRes is error'), '下载失败', downloadUrl);
|
||||||
break;
|
throw new Error('fetchRes is error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs.writeFileSync(downloadPath, Buffer.from(await blob.arrayBuffer()));
|
fs.writeFileSync(downloadPath, Buffer.from(await blob.arrayBuffer()));
|
||||||
|
63
src/module/download/upload.ts
Normal file
63
src/module/download/upload.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import FormData from 'form-data';
|
||||||
|
export const handleResponse = async (err: any, res: any) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Upload failed:', err);
|
||||||
|
resolve({ code: 500, message: err });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 处理服务器响应
|
||||||
|
let body = '';
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
body += chunk;
|
||||||
|
});
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const res = JSON.parse(body);
|
||||||
|
resolve(res);
|
||||||
|
} catch (e) {
|
||||||
|
resolve({ code: 500, message: body });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const getFormParams = (opts: UploadOptions, headers: any): FormData.SubmitOptions => {
|
||||||
|
const url = new URL(opts.url);
|
||||||
|
if (opts.token) {
|
||||||
|
// url.searchParams.append('token', opts.token);
|
||||||
|
}
|
||||||
|
const value: FormData.SubmitOptions = {
|
||||||
|
path: url.pathname + url.search,
|
||||||
|
host: url.hostname,
|
||||||
|
method: 'POST',
|
||||||
|
protocol: url.protocol === 'https:' ? 'https:' : 'http:',
|
||||||
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer ' + opts.token,
|
||||||
|
...headers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
type UploadOptions = {
|
||||||
|
url: string | URL;
|
||||||
|
file?: string | Buffer | File;
|
||||||
|
token?: string;
|
||||||
|
form?: FormData;
|
||||||
|
};
|
||||||
|
export const upload = (opts: UploadOptions): Promise<{ code?: number; message?: string; [key: string]: any }> => {
|
||||||
|
const form = opts?.form || new FormData();
|
||||||
|
if (!opts.form) {
|
||||||
|
if (typeof opts.file === 'string') {
|
||||||
|
form.append('file', Buffer.from(opts.file));
|
||||||
|
} else {
|
||||||
|
form.append('file', opts.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const headers = form.getHeaders();
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
form.submit(getFormParams(opts, headers), (err, res) => {
|
||||||
|
handleResponse(err, res).then(resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
1
src/scripts/summary.md
Normal file
1
src/scripts/summary.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 汇总 23333
|
24
src/scripts/upload.ts
Normal file
24
src/scripts/upload.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { fetchLink } from '@/module/download/install.ts';
|
||||||
|
import { baseURL, storage } from '@/module/query.ts';
|
||||||
|
import { upload } from '@/module/download/upload.ts';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
const scriptPath = path.join(process.cwd(), 'src', 'scripts');
|
||||||
|
const sum = 'https://kevisual.xiongxiao.me/root/ai/kevisual/01-summary.md';
|
||||||
|
const download = async () => {
|
||||||
|
const { content } = await fetchLink(sum, { returnContent: true });
|
||||||
|
console.log(content.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
// download();
|
||||||
|
|
||||||
|
const uploadTest = async () => {
|
||||||
|
const file = fs.readFileSync(path.join(scriptPath, './summary.md'));
|
||||||
|
const token = storage.getItem('token');
|
||||||
|
// const res = await upload({ url: sum, file: '# 汇总 123', token });
|
||||||
|
const res = await upload({ url: sum, file: file, token });
|
||||||
|
console.log(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
uploadTest();
|
Loading…
x
Reference in New Issue
Block a user