添加filesystem
This commit is contained in:
154
packages/filesystem/baidu/baidu.ts
Normal file
154
packages/filesystem/baidu/baidu.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import IoC from "@App/app/ioc";
|
||||
import { SystemConfig } from "@App/pkg/config/config";
|
||||
import { AuthVerify } from "../auth";
|
||||
import FileSystem, { File, FileReader, FileWriter } from "../filesystem";
|
||||
import { joinPath } from "../utils";
|
||||
import { BaiduFileReader, BaiduFileWriter } from "./rw";
|
||||
|
||||
export default class BaiduFileSystem implements FileSystem {
|
||||
accessToken?: string;
|
||||
|
||||
path: string;
|
||||
|
||||
systemConfig: SystemConfig;
|
||||
|
||||
constructor(path?: string, accessToken?: string) {
|
||||
this.path = path || "/apps";
|
||||
this.accessToken = accessToken;
|
||||
this.systemConfig = IoC.instance(SystemConfig) as SystemConfig;
|
||||
}
|
||||
|
||||
async verify(): Promise<void> {
|
||||
const token = await AuthVerify("baidu");
|
||||
this.accessToken = token;
|
||||
return this.list().then();
|
||||
}
|
||||
|
||||
open(file: File): Promise<FileReader> {
|
||||
// 获取fsid
|
||||
return Promise.resolve(new BaiduFileReader(this, file));
|
||||
}
|
||||
|
||||
openDir(path: string): Promise<FileSystem> {
|
||||
return Promise.resolve(
|
||||
new BaiduFileSystem(joinPath(this.path, path), this.accessToken)
|
||||
);
|
||||
}
|
||||
|
||||
create(path: string): Promise<FileWriter> {
|
||||
return Promise.resolve(
|
||||
new BaiduFileWriter(this, joinPath(this.path, path))
|
||||
);
|
||||
}
|
||||
|
||||
createDir(dir: string): Promise<void> {
|
||||
dir = joinPath(this.path, dir);
|
||||
const urlencoded = new URLSearchParams();
|
||||
urlencoded.append("path", dir);
|
||||
urlencoded.append("size", "0");
|
||||
urlencoded.append("isdir", "1");
|
||||
urlencoded.append("rtype", "3");
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
|
||||
return this.request(
|
||||
`https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=${this.accessToken}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: myHeaders,
|
||||
body: urlencoded,
|
||||
redirect: "follow",
|
||||
}
|
||||
).then((data) => {
|
||||
if (data.errno) {
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
request(url: string, config?: RequestInit) {
|
||||
config = config || {};
|
||||
const headers = <Headers>config.headers || new Headers();
|
||||
// 利用GM函数的匿名实现不发送cookie,因为某些情况cookie会导致-6错误
|
||||
headers.append(`${this.systemConfig.scriptCatFlag}-gm-xhr`, "true");
|
||||
headers.append(`${this.systemConfig.scriptCatFlag}-anonymous`, "true");
|
||||
config.headers = headers;
|
||||
return fetch(url, config)
|
||||
.then((data) => data.json())
|
||||
.then(async (data) => {
|
||||
if (data.errno === 111 || data.errno === -6) {
|
||||
const token = await AuthVerify("baidu", true);
|
||||
this.accessToken = token;
|
||||
url = url.replace(/access_token=[^&]+/, `access_token=${token}`);
|
||||
return fetch(url, config)
|
||||
.then((data2) => data2.json())
|
||||
.then((data2) => {
|
||||
if (data2.errno === 111 || data2.errno === -6) {
|
||||
throw new Error(JSON.stringify(data2));
|
||||
}
|
||||
return data2;
|
||||
});
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
delete(path: string): Promise<void> {
|
||||
const filelist = [joinPath(this.path, path)];
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
|
||||
return this.request(
|
||||
`https://pan.baidu.com/rest/2.0/xpan/file?method=filemanager&access_token=${this.accessToken}&opera=delete`,
|
||||
{
|
||||
method: "POST",
|
||||
body: `async=0&filelist=${encodeURIComponent(
|
||||
JSON.stringify(filelist)
|
||||
)}`,
|
||||
headers: myHeaders,
|
||||
}
|
||||
).then((data) => {
|
||||
if (data.errno) {
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
list(): Promise<File[]> {
|
||||
return this.request(
|
||||
`https://pan.baidu.com/rest/2.0/xpan/file?method=list&dir=${encodeURIComponent(
|
||||
this.path
|
||||
)}&order=time&access_token=${this.accessToken}`
|
||||
).then((data) => {
|
||||
if (data.errno) {
|
||||
if (data.errno === -9) {
|
||||
return [];
|
||||
}
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
const list: File[] = [];
|
||||
data.list.forEach((val: any) => {
|
||||
list.push({
|
||||
fsid: val.fs_id,
|
||||
name: val.server_filename,
|
||||
path: this.path,
|
||||
size: val.size,
|
||||
digest: val.md5,
|
||||
createtime: val.server_ctime * 1000,
|
||||
updatetime: val.server_mtime * 1000,
|
||||
});
|
||||
});
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
getDirUrl(): Promise<string> {
|
||||
return Promise.resolve(
|
||||
`https://pan.baidu.com/disk/main#/index?category=all&path=${encodeURIComponent(
|
||||
this.path
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
144
packages/filesystem/baidu/rw.ts
Normal file
144
packages/filesystem/baidu/rw.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { calculateMd5 } from "@App/pkg/utils/utils";
|
||||
import { MD5 } from "crypto-js";
|
||||
import { File, FileReader, FileWriter } from "../filesystem";
|
||||
import BaiduFileSystem from "./baidu";
|
||||
|
||||
export class BaiduFileReader implements FileReader {
|
||||
file: File;
|
||||
|
||||
fs: BaiduFileSystem;
|
||||
|
||||
constructor(fs: BaiduFileSystem, file: File) {
|
||||
this.fs = fs;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
async read(type?: "string" | "blob"): Promise<string | Blob> {
|
||||
// 查询文件信息获取dlink
|
||||
const data = await this.fs.request(
|
||||
`https://pan.baidu.com/rest/2.0/xpan/multimedia?method=filemetas&access_token=${
|
||||
this.fs.accessToken
|
||||
}&fsids=[${this.file.fsid!}]&dlink=1`
|
||||
);
|
||||
if (!data.list.length) {
|
||||
return Promise.reject(new Error("file not found"));
|
||||
}
|
||||
switch (type) {
|
||||
case "string":
|
||||
return fetch(
|
||||
`${data.list[0].dlink}&access_token=${this.fs.accessToken}`
|
||||
).then((resp) => resp.text());
|
||||
default: {
|
||||
return fetch(
|
||||
`${data.list[0].dlink}&access_token=${this.fs.accessToken}`
|
||||
).then((resp) => resp.blob());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BaiduFileWriter implements FileWriter {
|
||||
path: string;
|
||||
|
||||
fs: BaiduFileSystem;
|
||||
|
||||
constructor(fs: BaiduFileSystem, path: string) {
|
||||
this.fs = fs;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
size(content: string | Blob) {
|
||||
if (content instanceof Blob) {
|
||||
return content.size;
|
||||
}
|
||||
return new Blob([content]).size;
|
||||
}
|
||||
|
||||
async md5(content: string | Blob) {
|
||||
if (content instanceof Blob) {
|
||||
return calculateMd5(content);
|
||||
}
|
||||
return MD5(content).toString();
|
||||
}
|
||||
|
||||
async write(content: string | Blob): Promise<void> {
|
||||
// 预上传获取id
|
||||
const size = this.size(content).toString();
|
||||
const md5 = await this.md5(content);
|
||||
const blockList: string[] = [md5];
|
||||
let urlencoded = new URLSearchParams();
|
||||
urlencoded.append("path", this.path);
|
||||
urlencoded.append("size", size);
|
||||
urlencoded.append("isdir", "0");
|
||||
urlencoded.append("autoinit", "1");
|
||||
urlencoded.append("rtype", "3");
|
||||
urlencoded.append("block_list", JSON.stringify(blockList));
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
|
||||
const uploadid = await this.fs
|
||||
.request(
|
||||
`http://pan.baidu.com/rest/2.0/xpan/file?method=precreate&access_token=${this.fs.accessToken}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: myHeaders,
|
||||
body: urlencoded,
|
||||
}
|
||||
)
|
||||
.then((data) => {
|
||||
if (data.errno) {
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
return data.uploadid;
|
||||
});
|
||||
const body = new FormData();
|
||||
if (content instanceof Blob) {
|
||||
// 分片上传
|
||||
body.append("file", content);
|
||||
} else {
|
||||
body.append("file", new Blob([content]));
|
||||
}
|
||||
|
||||
await this.fs
|
||||
.request(
|
||||
`${
|
||||
`https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?method=upload&access_token=${this.fs.accessToken}` +
|
||||
`&type=tmpfile&path=`
|
||||
}${encodeURIComponent(this.path)}&uploadid=${uploadid}&partseq=0`,
|
||||
{
|
||||
method: "POST",
|
||||
body,
|
||||
}
|
||||
)
|
||||
.then((data) => {
|
||||
if (data.errno) {
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
return data;
|
||||
});
|
||||
// 创建文件
|
||||
urlencoded = new URLSearchParams();
|
||||
urlencoded.append("path", this.path);
|
||||
urlencoded.append("size", size);
|
||||
urlencoded.append("isdir", "0");
|
||||
urlencoded.append("block_list", JSON.stringify(blockList));
|
||||
urlencoded.append("uploadid", uploadid);
|
||||
urlencoded.append("rtype", "3");
|
||||
return this.fs
|
||||
.request(
|
||||
`https://pan.baidu.com/rest/2.0/xpan/file?method=create&access_token=${this.fs.accessToken}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: myHeaders,
|
||||
body: urlencoded,
|
||||
}
|
||||
)
|
||||
.then((data) => {
|
||||
if (data.errno) {
|
||||
throw new Error(JSON.stringify(data));
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user