mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-12-05 10:31:56 +00:00
feat:oplist上传下载文件实现
This commit is contained in:
parent
fcd50a2569
commit
4310e94547
@ -1,6 +1,6 @@
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { AppConfigService } from '../../config/config.service';
|
||||
import { DirectoryList, FileInfo, UserInfo } from './openlist.types';
|
||||
import { FileInfo, FsList } from './openlist.types';
|
||||
import { OpenListUtils } from './openlist.utils';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@ -64,29 +64,12 @@ export class OpenListService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
* @returns 用户信息
|
||||
*/
|
||||
public async getUserInfo(): Promise<UserInfo> {
|
||||
try {
|
||||
const token = await this.fetchToken(
|
||||
<string>this.configService.get('OPENLIST_API_BASE_USERNAME'),
|
||||
<string>this.configService.get('OPENLIST_API_BASE_PASSWORD'),
|
||||
);
|
||||
return await OpenListUtils.getUserInfo(token);
|
||||
} catch (error) {
|
||||
this.logger.error('获取用户信息失败:', error);
|
||||
throw new Error('获取用户信息失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出目录下的所有文件
|
||||
* @param path 目录路径
|
||||
* @returns 目录下的文件列表
|
||||
*/
|
||||
public async listFiles(path: string): Promise<DirectoryList[]> {
|
||||
public async listFiles(path: string): Promise<FsList> {
|
||||
try {
|
||||
const token = await this.fetchToken(
|
||||
<string>this.configService.get('OPENLIST_API_BASE_USERNAME'),
|
||||
@ -142,14 +125,19 @@ export class OpenListService {
|
||||
* 上传文件
|
||||
* @param filePath 上传路径
|
||||
* @param file 文件
|
||||
* @param filePathOnserver 服务器路径
|
||||
*/
|
||||
public async uploadFile(filePath: string, file: any): Promise<void> {
|
||||
public async uploadFile(
|
||||
filePath: string,
|
||||
file: any,
|
||||
filePathOnserver: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const token = await this.fetchToken(
|
||||
<string>this.configService.get('OPENLIST_API_BASE_USERNAME'),
|
||||
<string>this.configService.get('OPENLIST_API_BASE_PASSWORD'),
|
||||
);
|
||||
await OpenListUtils.uploadFile(token, filePath, file);
|
||||
await OpenListUtils.uploadFile(token, filePath, filePathOnserver, file);
|
||||
} catch (error) {
|
||||
this.logger.error('上传文件失败:', error);
|
||||
throw new Error('上传文件失败');
|
||||
|
||||
@ -1,25 +1,63 @@
|
||||
export interface UserInfo {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
role: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface DirectoryList {
|
||||
path: string;
|
||||
name: string;
|
||||
is_directory: boolean;
|
||||
size: number;
|
||||
modified_at: string;
|
||||
/**
|
||||
* /api/fs/list 文件目录列表
|
||||
*/
|
||||
export interface FsList {
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
content: [
|
||||
name: string,
|
||||
size: number,
|
||||
is_dir: boolean,
|
||||
modified: string, //修改时间
|
||||
sign: string, //签名
|
||||
thumb: string, //略缩图
|
||||
type: number, //类型
|
||||
];
|
||||
total: number; //总数
|
||||
readme: string; //说明?
|
||||
write: boolean; //是否可写入
|
||||
provider: string;
|
||||
header: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* /api/fs/get 获取文件/目录信息
|
||||
*/
|
||||
export interface FileInfo {
|
||||
path: string;
|
||||
size: number;
|
||||
mime_type: string;
|
||||
created_at: string;
|
||||
modified_at: string;
|
||||
is_directory: boolean;
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
name: string;
|
||||
size: number;
|
||||
is_dir: boolean;
|
||||
modified: string;
|
||||
sign: string;
|
||||
thumb: string;
|
||||
type: number;
|
||||
raw_url: string; //原始url
|
||||
readme: string;
|
||||
provider: string;
|
||||
created: string; //创建时间
|
||||
header: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* /api/fs/put 流式上传文件
|
||||
*/
|
||||
export interface FileUpload {
|
||||
code: number;
|
||||
message: string;
|
||||
data: {
|
||||
task: {
|
||||
id: string;
|
||||
name: string;
|
||||
state: number;
|
||||
status: string;
|
||||
progress: number;
|
||||
error: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import axios from 'axios';
|
||||
import { AppConfigService } from '../../config/config.service';
|
||||
import { Inject, Logger } from '@nestjs/common';
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import { FileInfo, FileUpload, FsList } from './openlist.types';
|
||||
|
||||
export class OpenListUtils {
|
||||
private static readonly logger = new Logger(OpenListUtils.name);
|
||||
@ -27,10 +27,10 @@ export class OpenListUtils {
|
||||
username: username,
|
||||
password: password,
|
||||
});
|
||||
this.logger.debug(response);
|
||||
//this.logger.debug(response);
|
||||
if (response.data.data.token) {
|
||||
const token: string = response.data.data.token;
|
||||
this.logger.log(`获取Token成功: ${token}`);
|
||||
this.logger.debug(`获取Token成功: ${token}`);
|
||||
return token;
|
||||
} else {
|
||||
this.logger.error(`获取Token失败: ${response.data.data.message}`);
|
||||
@ -42,45 +42,23 @@ export class OpenListUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
* @param token 用户 Token
|
||||
* @returns 用户信息
|
||||
*/
|
||||
static async getUserInfo(token: string): Promise<any> {
|
||||
const url = `${this.apiBaseUrl}/auth/userinfo`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
this.logger.log('获取用户信息成功..');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('获取用户信息失败..', error);
|
||||
throw new Error('获取用户信息失败..');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目录列表
|
||||
* @param token 用户 Token
|
||||
* @param path 目录路径
|
||||
* @returns 文件目录列表
|
||||
*/
|
||||
static async listDirectory(token: string, path: string): Promise<any> {
|
||||
const url = `${this.apiBaseUrl}/fs/list`;
|
||||
|
||||
static async listDirectory(token: string, path: string): Promise<FsList> {
|
||||
const url = `${this.apiBaseUrl}/api/fs/list`;
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
params: { path },
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
this.logger.log('列出目录成功..');
|
||||
this.logger.log(`列出目录${path}成功..`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('列出目录失败..', error);
|
||||
throw new Error('列出目录失败..');
|
||||
this.logger.error(`列出目录${path}失败..`, error);
|
||||
throw new Error(`列出目录${path}失败..`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,11 +66,9 @@ export class OpenListUtils {
|
||||
* 获取某个文件的详细信息
|
||||
* @param token 用户 Token
|
||||
* @param filePath 文件路径
|
||||
* @returns 文件信息
|
||||
*/
|
||||
static async getFileInfo(token: string, filePath: string): Promise<any> {
|
||||
static async getFileInfo(token: string, filePath: string): Promise<FileInfo> {
|
||||
const url = `${this.apiBaseUrl}/fs/info`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
params: { path: filePath },
|
||||
@ -106,36 +82,6 @@ export class OpenListUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件重命名
|
||||
* @param token 用户 Token
|
||||
* @param oldPath 旧路径
|
||||
* @param newPath 新路径
|
||||
* @returns 重命名结果
|
||||
*/
|
||||
static async renameFile(
|
||||
token: string,
|
||||
oldPath: string,
|
||||
newPath: string,
|
||||
): Promise<any> {
|
||||
const url = `${this.apiBaseUrl}/fs/rename`;
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
url,
|
||||
{ oldPath, newPath },
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
);
|
||||
this.logger.log(`文件重命名成功: ${oldPath} => ${newPath}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('文件重命名失败..', error);
|
||||
throw new Error('文件重命名失败..');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param token 用户 Token
|
||||
@ -147,24 +93,24 @@ export class OpenListUtils {
|
||||
filePath: string,
|
||||
downloadPath: string,
|
||||
): Promise<void> {
|
||||
const url = `${this.apiBaseUrl}/fs/download`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
params: { path: filePath },
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
const fileInfo = await this.getFileInfo(token, filePath);
|
||||
const rawUrl = fileInfo.data.raw_url;
|
||||
if (!rawUrl) {
|
||||
this.logger.error('文件没有找到 raw_url 地址..');
|
||||
throw new Error('文件没有找到 raw_url 地址..');
|
||||
}
|
||||
const response = await axios.get(rawUrl, {
|
||||
responseType: 'stream',
|
||||
});
|
||||
const writer = fs.createWriteStream(downloadPath);
|
||||
response.data.pipe(writer);
|
||||
|
||||
writer.on('finish', () => {
|
||||
this.logger.log(`文件下载成功: ${downloadPath}`);
|
||||
});
|
||||
|
||||
writer.on('error', (error) => {
|
||||
this.logger.error('下载文件失败', error);
|
||||
throw new Error('下载文件失败');
|
||||
throw new Error('下载文件失败..');
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('下载文件失败..', error);
|
||||
@ -173,68 +119,39 @@ export class OpenListUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* 流式上传文件
|
||||
* @param token 用户 Token
|
||||
* @param filePath 上传文件的路径
|
||||
* @param file 上传文件的内容
|
||||
* @returns 上传结果
|
||||
* @param filePathOnServer 服务器上保存的文件路径
|
||||
* @param file 文件流
|
||||
*/
|
||||
static async uploadFile(
|
||||
token: string,
|
||||
filePath: string,
|
||||
file: any,
|
||||
): Promise<any> {
|
||||
const url = `${this.apiBaseUrl}/fs/upload`;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('path', filePath);
|
||||
filePathOnServer: string,
|
||||
file: fs.ReadStream,
|
||||
): Promise<FileUpload> {
|
||||
const url = `${this.apiBaseUrl}/api/fs/put`;
|
||||
const headers = {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': file.bytesRead,
|
||||
'File-Path': encodeURIComponent(filePathOnServer),
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await axios.post(url, formData, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
const response = await axios.put(url, file, {
|
||||
headers,
|
||||
params: {
|
||||
path: filePath,
|
||||
'As-Task': 'true', //作为任务
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(`文件上传成功: ${filePath}`);
|
||||
this.logger.log(`文件上传成功: ${filePathOnServer}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('上传文件失败..', error);
|
||||
throw new Error('上传文件失败..');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个目录下的所有文件
|
||||
* @param token 用户 Token
|
||||
* @param directoryPath 目录路径
|
||||
* @returns 文件列表
|
||||
*/
|
||||
static async listFilesInDirectory(
|
||||
token: string,
|
||||
directoryPath: string,
|
||||
): Promise<any[]> {
|
||||
const directoryInfo = await this.listDirectory(token, directoryPath);
|
||||
return directoryInfo.filter(
|
||||
(item: { is_directory: any }) => !item.is_directory,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件更新
|
||||
* @param token 用户 Token
|
||||
* @param filePath 文件路径
|
||||
* @param lastModified 上次改动时间
|
||||
* @returns 文件是否更新
|
||||
*/
|
||||
static async checkFileUpdate(
|
||||
token: string,
|
||||
filePath: string,
|
||||
lastModified: string,
|
||||
): Promise<boolean> {
|
||||
const fileInfo = await this.getFileInfo(token, filePath);
|
||||
return fileInfo.modified_at !== lastModified;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user