md/src/utils/file.js
2024-08-18 19:49:16 +08:00

342 lines
10 KiB
JavaScript

import CryptoJS from 'crypto-js'
import OSS from 'ali-oss'
import * as Minio from 'minio'
import COS from 'cos-js-sdk-v5'
import Buffer from 'buffer-from'
import { v4 as uuidv4 } from 'uuid'
import * as qiniu from 'qiniu-js'
import fetch from '@/utils/fetch'
import { base64encode, safe64, utf16to8 } from '@/utils/tokenTools'
import * as tokenTools from '@/utils/tokenTools'
import { giteeConfig, githubConfig } from '@/config'
function getConfig(useDefault, platform) {
if (useDefault) {
// load default config file
const config = platform === `github` ? githubConfig : giteeConfig
const { username, repoList, branch, accessTokenList } = config
// choose random token from access_token list
const tokenIndex = Math.floor(Math.random() * accessTokenList.length)
const accessToken = accessTokenList[tokenIndex].replace(`doocsmd`, ``)
// choose random repo from repo list
const repoIndex = Math.floor(Math.random() * repoList.length)
const repo = repoList[repoIndex]
return { username, repo, branch, accessToken }
}
// load configuration from localStorage
const customConfig = JSON.parse(localStorage.getItem(`${platform}Config`))
// split username/repo
const repoUrl = customConfig.repo
.replace(`https://${platform}.com/`, ``)
.replace(`http://${platform}.com/`, ``)
.replace(`${platform}.com/`, ``)
.split(`/`)
return {
username: repoUrl[0],
repo: repoUrl[1],
branch: customConfig.branch || `master`,
accessToken: customConfig.accessToken,
}
}
/**
* 获取 `年/月/日` 形式的目录
* @returns string
*/
function getDir() {
const date = new Date()
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, `0`)
const day = date.getDate().toString().padStart(2, `0`)
return `${year}/${month}/${day}`
}
/**
* 根据文件名获取它以 `时间戳+uuid` 的形式
* @param {string} filename 文件名
* @returns {string} `时间戳+uuid`
*/
function getDateFilename(filename) {
const currentTimestamp = new Date().getTime()
const fileSuffix = filename.split(`.`)[1]
return `${currentTimestamp}-${uuidv4()}.${fileSuffix}`
}
// -----------------------------------------------------------------------
// GitHub File Upload
// -----------------------------------------------------------------------
async function ghFileUpload(content, filename) {
const useDefault = localStorage.getItem(`imgHost`) === `default`
const { username, repo, branch, accessToken } = getConfig(
useDefault,
`github`,
)
const dir = getDir()
const url = `https://api.github.com/repos/${username}/${repo}/contents/${dir}/`
const dateFilename = getDateFilename(filename)
const res = await fetch({
url: url + dateFilename,
method: `put`,
headers: {
Authorization: `token ${accessToken}`,
},
data: {
content,
branch,
message: `Upload by ${window.location.href}`,
},
})
const githubResourceUrl = `raw.githubusercontent.com/${username}/${repo}/${branch}/`
const cdnResourceUrl = `fastly.jsdelivr.net/gh/${username}/${repo}@${branch}/`
res.content = res.data?.content || res.content
return useDefault
? res.content.download_url.replace(githubResourceUrl, cdnResourceUrl)
: res.content.download_url
}
// -----------------------------------------------------------------------
// Gitee File Upload
// -----------------------------------------------------------------------
async function giteeUpload(content, filename) {
const useDefault = localStorage.getItem(`imgHost`) === `default`
const { username, repo, branch, accessToken } = getConfig(useDefault, `gitee`)
const dir = getDir()
const dateFilename = getDateFilename(filename)
const url = `https://gitee.com/api/v5/repos/${username}/${repo}/contents/${dir}/${dateFilename}`
const res = await fetch({
url,
method: `POST`,
data: {
content,
branch,
access_token: accessToken,
message: `Upload by ${window.location.href}`,
},
})
res.content = res.data?.content || res.content
return encodeURI(res.content.download_url)
}
// -----------------------------------------------------------------------
// Qiniu File Upload
// -----------------------------------------------------------------------
function getQiniuToken(accessKey, secretKey, putPolicy) {
const policy = JSON.stringify(putPolicy)
const encoded = base64encode(utf16to8(policy))
const hash = CryptoJS.HmacSHA1(encoded, secretKey)
const encodedSigned = hash.toString(CryptoJS.enc.Base64)
return `${accessKey}:${safe64(encodedSigned)}:${encoded}`
}
async function qiniuUpload(file) {
const { accessKey, secretKey, bucket, region, path, domain } = JSON.parse(
localStorage.getItem(`qiniuConfig`),
)
const token = getQiniuToken(accessKey, secretKey, {
scope: bucket,
deadline: Math.trunc(new Date().getTime() / 1000) + 3600,
})
const dir = path ? `${path}/` : ``
const dateFilename = dir + getDateFilename(file.name)
const observable = qiniu.upload(file, dateFilename, token, {}, { region })
return new Promise((resolve, reject) => {
observable.subscribe({
next: (result) => {
console.log(result)
},
error: (err) => {
reject(err.message)
},
complete: (result) => {
resolve(`${domain}/${result.key}`)
},
})
})
}
// -----------------------------------------------------------------------
// AliOSS File Upload
// -----------------------------------------------------------------------
async function aliOSSFileUpload(content, filename) {
const dateFilename = getDateFilename(filename)
const { region, bucket, accessKeyId, accessKeySecret, cdnHost, path }
= JSON.parse(localStorage.getItem(`aliOSSConfig`))
const buffer = Buffer(content, `base64`)
const dir = `${path}/${dateFilename}`
const client = new OSS({
region,
bucket,
accessKeyId,
accessKeySecret,
})
try {
const res = await client.put(dir, buffer)
if (cdnHost === ``)
return res.url
return `${cdnHost}/${path === `` ? dateFilename : dir}`
}
catch (e) {
return Promise.reject(e)
}
}
// -----------------------------------------------------------------------
// TxCOS File Upload
// -----------------------------------------------------------------------
async function txCOSFileUpload(file) {
const dateFilename = getDateFilename(file.name)
const { secretId, secretKey, bucket, region, path, cdnHost } = JSON.parse(
localStorage.getItem(`txCOSConfig`),
)
const cos = new COS({
SecretId: secretId,
SecretKey: secretKey,
})
return new Promise((resolve, reject) => {
cos.putObject(
{
Bucket: bucket,
Region: region,
Key: `${path}/${dateFilename}`,
Body: file,
},
(err, data) => {
if (err) {
reject(err)
}
else if (cdnHost) {
resolve(
path === ``
? `${cdnHost}/${dateFilename}`
: `${cdnHost}/${path}/${dateFilename}`,
)
}
else {
resolve(`https://${data.Location}`)
}
},
)
})
}
// -----------------------------------------------------------------------
// Minio File Upload
// -----------------------------------------------------------------------
async function minioFileUpload(content, filename) {
const dateFilename = getDateFilename(filename)
const { endpoint, port, useSSL, bucket, accessKey, secretKey } = JSON.parse(
localStorage.getItem(`minioConfig`),
)
const buffer = Buffer(content, `base64`)
const conf = {
endPoint: endpoint,
useSSL,
accessKey,
secretKey,
}
const p = Number(port || 0)
const isCustomPort = p > 0 && p !== 80 && p !== 443
if (isCustomPort) {
conf.port = p
}
return new Promise((resolve, reject) => {
const minioClient = new Minio.Client(conf)
try {
minioClient.putObject(bucket, dateFilename, buffer, (e) => {
if (e) {
reject(e)
}
const host = `${useSSL ? `https://` : `http://`}${endpoint}${
isCustomPort ? `:${port}` : ``
}`
const url = `${host}/${bucket}/${dateFilename}`
// console.log("文件上传成功: ", url)
resolve(url)
// return `${endpoint}/${bucket}/${dateFilename}`;
})
}
catch (e) {
reject(e)
}
})
}
// -----------------------------------------------------------------------
// formCustom File Upload
// -----------------------------------------------------------------------
async function formCustomUpload(content, file) {
const str = `
async (CUSTOM_ARG) => {
${localStorage.getItem(`formCustomConfig`)}
}
`
return new Promise((resolve, reject) => {
const exportObj = {
content, // 待上传图片的 base64
file, // 待上传图片的 file 对象
util: {
axios: fetch, // axios 实例
CryptoJS, // 加密库
OSS, // ali-oss
COS, // cos-js-sdk-v5
Buffer, // buffer-from
uuidv4, // uuid
qiniu, // qiniu-js
tokenTools, // 一些编码转换函数
getDir, // 获取 年/月/日 形式的目录
getDateFilename, // 根据文件名获取它以 时间戳+uuid 的形式
},
okCb: resolve, // 重要: 上传成功后给此回调传 url 即可
errCb: reject, // 上传失败调用的函数
}
// eslint-disable-next-line no-eval
eval(str)(exportObj).catch((err) => {
console.error(err)
reject(err)
})
})
}
function fileUpload(content, file) {
const imgHost = localStorage.getItem(`imgHost`)
!imgHost && localStorage.setItem(`imgHost`, `default`)
switch (imgHost) {
case `aliOSS`:
return aliOSSFileUpload(content, file.name)
case `minio`:
return minioFileUpload(content, file.name)
case `txCOS`:
return txCOSFileUpload(file)
case `qiniu`:
return qiniuUpload(file)
case `gitee`:
return giteeUpload(content, file.name)
case `github`:
return ghFileUpload(content, file.name)
case `formCustom`:
return formCustomUpload(content, file)
default:
// return file.size / 1024 < 1024
// ? giteeUpload(content, file.name)
// : ghFileUpload(content, file.name);
return ghFileUpload(content, file.name)
}
}
export default {
fileUpload,
}