|
|
|
/*
|
|
|
|
* fs.ts
|
|
|
|
* Copyright (C) 2023 veypi <i@veypi.com>
|
|
|
|
* 2023-10-08 01:55
|
|
|
|
* Distributed under terms of the MIT license.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import * as webdav from 'webdav'
|
|
|
|
import { proxy } from "./v2dom";
|
|
|
|
import logic from "./logic";
|
|
|
|
|
|
|
|
export interface fileProps {
|
|
|
|
filename: string,
|
|
|
|
basename: string,
|
|
|
|
lastmod: string,
|
|
|
|
size: number,
|
|
|
|
type: "directory" | "file",
|
|
|
|
etag: string
|
|
|
|
}
|
|
|
|
|
|
|
|
function delay(ms: number) {
|
|
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
}
|
|
|
|
|
|
|
|
class davWraper {
|
|
|
|
private client: webdav.WebDAVClient
|
|
|
|
private host: string
|
|
|
|
private prefix: string
|
|
|
|
private token: string
|
|
|
|
constructor(host: string, prefix: string, token: string) {
|
|
|
|
this.host = host
|
|
|
|
this.prefix = prefix
|
|
|
|
this.token = token
|
|
|
|
this.client = webdav.createClient(host + prefix)
|
|
|
|
if (this.prefix.endsWith('/')) {
|
|
|
|
this.prefix = this.prefix.slice(0, -1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set(k: 'host' | 'token', value: string) {
|
|
|
|
if (value !== this[k]) {
|
|
|
|
this[k] = value
|
|
|
|
if (k === 'token') {
|
|
|
|
this.client.setHeaders({
|
|
|
|
authorization: "bearer " + value
|
|
|
|
})
|
|
|
|
} else if (k === 'host') {
|
|
|
|
this.client = webdav.createClient(this.host + this.prefix)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
putFileContents(filename: string, data: string, options?: webdav.PutFileContentsOptions) {
|
|
|
|
return this.retry(() => this.client.putFileContents(filename, data, options))
|
|
|
|
}
|
|
|
|
getFileContents(filename: string, options?: webdav.GetFileContentsOptions) {
|
|
|
|
return this.retry(() => this.client.getFileContents(filename, options))
|
|
|
|
}
|
|
|
|
getDirectoryContents(path: string, options?: webdav.GetDirectoryContentsOptions) {
|
|
|
|
return this.retry(() => this.client.getDirectoryContents(path, options))
|
|
|
|
}
|
|
|
|
stat(path: string, options?: webdav.StatOptions) {
|
|
|
|
return this.retry(() => this.client.stat(path, options))
|
|
|
|
}
|
|
|
|
urlwrap(path: string) {
|
|
|
|
if (path.startsWith('/')) {
|
|
|
|
return this.prefix + path
|
|
|
|
} else {
|
|
|
|
return this.prefix + '/' + path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
urlunwrap(url: string) {
|
|
|
|
if (url.startsWith(this.prefix)) {
|
|
|
|
return url.slice(this.prefix.length)
|
|
|
|
}
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
private retry<T>(fn: () => Promise<T>): Promise<T> {
|
|
|
|
let retries = 0;
|
|
|
|
function attempt(): Promise<T> {
|
|
|
|
return fn().catch(error => {
|
|
|
|
if (retries < 3) {
|
|
|
|
retries++;
|
|
|
|
console.log(`Attempt ${retries} failed, retrying after 1 second...`);
|
|
|
|
return delay(1000).then(attempt);
|
|
|
|
} else {
|
|
|
|
// 超过最大重试次数后不再重试
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return attempt()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let token = logic.token.oa.raw()
|
|
|
|
const user = new davWraper(logic.Host(), '/fs/u/', token)
|
|
|
|
const app = new davWraper(logic.Host(), '/fs/a/', token)
|
|
|
|
|
|
|
|
|
|
|
|
export const set_host = (h: string) => {
|
|
|
|
user.set('host', h)
|
|
|
|
app.set('host', h)
|
|
|
|
}
|
|
|
|
const sync = () => {
|
|
|
|
if (logic.token.oa.isVaild()) {
|
|
|
|
let t = logic.token.oa.raw()
|
|
|
|
// console.warn('sync oafs token: ' + t)
|
|
|
|
user.set('token', t)
|
|
|
|
app.set('token', t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
proxy.Listen(() => {
|
|
|
|
sync()
|
|
|
|
})
|
|
|
|
|
|
|
|
const rename = (o: string, n?: string) => {
|
|
|
|
let ext = '.' + o.split('.').pop()?.toLowerCase()
|
|
|
|
if (n) {
|
|
|
|
return n + ext
|
|
|
|
}
|
|
|
|
let d = new Date().getTime()
|
|
|
|
return d + o + ext
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// const get = (url: string): Promise<string> => {
|
|
|
|
// return fetch(cfg.Host() + url, { headers: { authorization: "bearer " + cfg.oa_token.value } }).then((response) => response.text())
|
|
|
|
// }
|
|
|
|
|
|
|
|
// rename 可以保持url不变
|
|
|
|
// const upload = (f: FileList | File[], dir?: string, renames?: string[]) => {
|
|
|
|
// return new Promise<string[]>((resolve, reject) => {
|
|
|
|
// var data = new FormData();
|
|
|
|
// for (let i = 0; i < f.length; i++) {
|
|
|
|
// let nf = new File([f[i]], rename(f[i].name, renames && renames[i] ? renames[i] : undefined), { type: f[i].type })
|
|
|
|
// data.append('files', nf, nf.name)
|
|
|
|
// }
|
|
|
|
// axios.post("/api/upload/" + (dir || ''), data, {
|
|
|
|
// headers: {
|
|
|
|
// "Content-Type": 'multipart/form-data',
|
|
|
|
// 'auth_token': cfg.oa_token.value,
|
|
|
|
// }
|
|
|
|
// }).then(e => {
|
|
|
|
// resolve(e.data)
|
|
|
|
// }).catch(reject)
|
|
|
|
// })
|
|
|
|
// }
|
|
|
|
|
|
|
|
const get_dav = (client: webdav.WebDAVClient, base_url: string) => {
|
|
|
|
return {
|
|
|
|
client: client,
|
|
|
|
stat: client.stat,
|
|
|
|
dir: client.getDirectoryContents,
|
|
|
|
uploadstr: (dir: string, name: string, data: string) => {
|
|
|
|
if (dir.startsWith('/')) {
|
|
|
|
dir = dir.slice(1)
|
|
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let temp = () => {
|
|
|
|
let reader = new FileReader()
|
|
|
|
reader.onload = function (event) {
|
|
|
|
var res = event.target?.result
|
|
|
|
// let data = new Blob([res])
|
|
|
|
client.putFileContents(dir + name, res).then(e => {
|
|
|
|
if (e) {
|
|
|
|
resolve(base_url + dir + name)
|
|
|
|
}
|
|
|
|
}).catch(reject)
|
|
|
|
}
|
|
|
|
reader.readAsArrayBuffer(new Blob([data], { type: 'plain/text' }))
|
|
|
|
}
|
|
|
|
client.stat(dir).then(() => {
|
|
|
|
temp()
|
|
|
|
}).catch((_) => {
|
|
|
|
client.createDirectory(dir, { recursive: true }).then(() => {
|
|
|
|
temp()
|
|
|
|
}).catch(e => {
|
|
|
|
console.warn(e)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
user,
|
|
|
|
app,
|
|
|
|
rename,
|
|
|
|
}
|
|
|
|
|