import * as vscode from 'vscode';
import { UploadType, CustomUploader, BackfillImageProps, BackfillImage } from '../types';
import axios, { AxiosResponse } from 'axios';
export interface FileInfo {
name: string;
type: string;
path: string;
size: number;
}
export interface UploadFileHandlerRes extends BackfillImage {
name: string;
url: string;
poster?: string;
}
export const uploadFileHandler = async (fileInfo: FileInfo): Promise<UploadFileHandlerRes> => {
const { name = '', type = '', path = '' } = fileInfo;
const uploadType = vscode.workspace.getConfiguration('cherryMarkdown').get<UploadType>('UploadType');
const res: UploadFileHandlerRes = { name, url: '' };
const backfillImageProps = vscode.workspace
.getConfiguration('cherryMarkdown')
.get<BackfillImageProps>('BackfillImageProps', []);
if (Array.isArray(backfillImageProps)) {
backfillImageProps.forEach((prop) => {
(res as any)[prop] = true;
});
}
switch (uploadType) {
case 'CustomUploader': {
const customUploader = vscode.workspace.getConfiguration('cherryMarkdown').get<CustomUploader>('CustomUploader');
if (!customUploader || customUploader.enable !== true) {
vscode.window.showInformationMessage('请完善自定义上传配置');
throw new Error('请完善自定义上传配置');
}
if (!/^(http|https):\/\//.test(customUploader.url)) {
vscode.window.showInformationMessage('自定义上传地址格式不正确');
throw new Error('自定义上传地址格式不正确');
}
const file = await vscode.workspace.fs.readFile(vscode.Uri.file(path));
const userHeaders =
customUploader.headers && typeof customUploader.headers === 'object' ? customUploader.headers : {};
const headers: Record<string, string> = { ...userHeaders };
if (!headers['Content-Type'] && !headers['content-type']) {
headers['Content-Type'] = 'application/octet-stream';
}
if (!headers['X-File-Name'] && !headers['x-file-name']) {
headers['X-File-Name'] = name;
}
try {
const customUpload = await axios.post(customUploader.url, file, { headers, responseType: 'json' });
const { data } = customUpload;
if (!data) {
throw new Error('Empty response from uploader');
}
if (typeof data === 'string') {
res.url = data;
} else if (data.url) {
res.url = data.url;
} else if (data.result && Array.isArray(data.result) && data.result[0]) {
const [firstResult] = data.result;
res.url = firstResult;
} else if (data.data && typeof data.data === 'string') {
res.url = data.data;
} else if (data.data && data.data.url) {
res.url = data.data.url;
} else {
const firstUrl = Object.values(data).find((v) => typeof v === 'string' && /^(http|data:image)/.test(v));
if (typeof firstUrl === 'string') {
res.url = firstUrl;
}
}
if (!res.url) {
throw new Error('无法从上传响应中解析出 URL');
}
} catch (err: any) {
vscode.window.showErrorMessage(`自定义上传失败:${err?.message || err}`);
throw err;
}
break;
}
case 'PicGoServer': {
const picGoServer = vscode.workspace
.getConfiguration('cherryMarkdown')
.get<string>('PicGoServer', 'http://127.0.0.1:36677/upload');
const upload = await axios.post<any, AxiosResponse<{ success: boolean; result: string[] }>>(
picGoServer,
{ list: [path] },
{ headers: { 'Content-Type': 'application/json' } },
);
if (upload.data?.success !== true) {
throw new Error('上传失败');
}
res.url = upload.data?.result?.[0] ?? '';
break;
}
default: {
if (type.startsWith('image')) {
const file = await vscode.workspace.fs.readFile(vscode.Uri.file(path));
const base64 = Buffer.from(file).toString('base64');
res.url = `data:${type};base64,${base64}`;
} else {
vscode.window.showInformationMessage('未指定上传服务时暂时只支持图片');
throw new Error('未指定上传服务时暂时只支持图片');
}
break;
}
}
return res;
};