bun 多文件上传会有问题
This commit is contained in:
parent
cdbebe92d0
commit
4aec2bc231
15
package.json
15
package.json
@ -25,7 +25,8 @@
|
||||
"bun.config.mjs"
|
||||
],
|
||||
"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",
|
||||
"postbuild": "cd assistant && pnpm build",
|
||||
"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/query": "0.0.17",
|
||||
"@kevisual/query-login": "0.0.5",
|
||||
"@types/bun": "^1.2.10",
|
||||
"@types/bun": "^1.2.13",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/jsonwebtoken": "^9.0.9",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^22.15.17",
|
||||
"chalk": "^5.4.1",
|
||||
"commander": "^13.1.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
"filesize": "^10.1.6",
|
||||
"form-data": "^4.0.2",
|
||||
"ignore": "^7.0.3",
|
||||
"inquirer": "^12.5.2",
|
||||
"ignore": "^7.0.4",
|
||||
"inquirer": "^12.6.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"rollup": "^4.40.0",
|
||||
"rollup": "^4.40.2",
|
||||
"rollup-plugin-dts": "^6.2.1",
|
||||
"tar": "^7.4.3",
|
||||
"zustand": "^5.0.3"
|
||||
"zustand": "^5.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"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 { program, Command } from '../../../program.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 fs from 'fs';
|
||||
import { getConfig } from '@/module/get-config.ts';
|
||||
@ -156,3 +156,20 @@ const uninstallAppCommand = new Command('uninstall')
|
||||
|
||||
appCommand.addCommand(downloadAppCommand);
|
||||
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 chalk from 'chalk';
|
||||
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
|
||||
* @returns
|
||||
@ -209,8 +211,10 @@ const uploadFiles = async (files: string[], directory: string, opts: UploadFileO
|
||||
console.log('文件已经上传过了', file);
|
||||
continue;
|
||||
}
|
||||
const filename = path.basename(filePath);
|
||||
console.log('upload file', file, filename);
|
||||
form.append('file', fs.createReadStream(filePath), {
|
||||
filename: file,
|
||||
filename: filename,
|
||||
filepath: file,
|
||||
});
|
||||
needUpload = true;
|
||||
@ -221,50 +225,12 @@ const uploadFiles = async (files: string[], directory: string, opts: UploadFileO
|
||||
code: 200,
|
||||
};
|
||||
}
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
const _baseURL = getBaseURL();
|
||||
const url = new URL('/api/s1/resources/upload', _baseURL);
|
||||
const searchParams = url.searchParams;
|
||||
if (opts.noCheckAppFiles) {
|
||||
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 });
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
const _baseURL = getBaseURL();
|
||||
const url = new URL('/api/s1/resources/upload', _baseURL);
|
||||
if (opts.noCheckAppFiles) {
|
||||
url.searchParams.append('noCheckAppFiles', 'true');
|
||||
}
|
||||
return upload({ url: url, form: form, token: token });
|
||||
};
|
||||
app.addCommand(command);
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { program as app, Command } from '@/program.ts';
|
||||
|
||||
const command = new Command('sync').description('同步项目').action(() => {
|
||||
console.log('同步项目');
|
||||
});
|
||||
const command = new Command('sync')
|
||||
.option('-d --dir <dir>')
|
||||
.description('同步项目')
|
||||
.action(() => {
|
||||
console.log('同步项目');
|
||||
});
|
||||
const syncUpload = new Command('upload').description('上传项目').action(() => {
|
||||
console.log('上传项目');
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { storage } from '../query.ts';
|
||||
import { storage, baseURL } from '../query.ts';
|
||||
import { chalk } from '../chalk.ts';
|
||||
|
||||
type DownloadTask = {
|
||||
@ -20,6 +20,40 @@ export type Package = {
|
||||
key?: string;
|
||||
[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 = {
|
||||
appDir?: string;
|
||||
kevisualUrl?: string;
|
||||
@ -65,20 +99,12 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
console.log('downloadUrwl', downloadUrl);
|
||||
const token = process.env.KEVISUAL_TOKEN || storage.getItem('token');
|
||||
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;
|
||||
const { blob, type } = await fetchLink(downloadUrl);
|
||||
if (type.includes('text/html')) {
|
||||
const html = await blob.text();
|
||||
if (html === 'fetchRes is error') {
|
||||
console.log(chalk.red('fetchRes is error'));
|
||||
break;
|
||||
console.log(chalk.red('fetchRes is error'), '下载失败', downloadUrl);
|
||||
throw new Error('fetchRes is error');
|
||||
}
|
||||
}
|
||||
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