Files
CloudFlare-ImgBed/functions/api/manage/sysConfig/upload.js
T
htazq 9c7a2b4336 Enable third-party WebDAV storage without new runtime dependencies
Cloudflare Workers and Pages already provide the Fetch/Web APIs needed for WebDAV verbs, so the storage integration uses a small local helper instead of adding a Node-oriented WebDAV client. The channel now participates in upload, read, delete, move, rename, channel listing, and runtime config, with chunked uploads explicitly guarded because WebDAV has no portable server-side compose primitive.

Constraint: Preserve Pages Functions and generated Worker deployment paths
Constraint: No new npm dependency for WebDAV client behavior
Rejected: Add a WebDAV npm client | likely Node API/compatibility and package-lock churn
Rejected: Treat WebDAV as External URL only | not a complete storage channel lifecycle
Confidence: high
Scope-risk: moderate
Directive: WebDAV here is third-party storage; keep it distinct from the built-in /dav server settings
Tested: npm test; node worker/generate-routes.js; npx wrangler deploy --dry-run --config worker/wrangler.toml; git diff --cached --check
Not-tested: Live third-party WebDAV provider credentials; Digest-only WebDAV authentication
2026-04-28 00:05:12 +08:00

336 lines
11 KiB
JavaScript

import { getDatabase } from '../../../utils/databaseAdapter.js';
import { normalizeWebDAVHeaders } from '../../../utils/webdavAPI.js';
export async function onRequest(context) {
// 上传设置相关,GET方法读取设置,POST方法保存设置
const {
request, // same as existing Worker API
env, // same as existing Worker API
params, // if filename includes [id] or [[path]]
waitUntil, // same as ctx.waitUntil in existing Worker API
next, // used for middleware or to fetch assets
data, // arbitrary space for passing data between middlewares
} = context;
const db = getDatabase(env);
// GET读取设置
if (request.method === 'GET') {
const settings = await getUploadConfig(db, env)
return new Response(JSON.stringify(settings), {
headers: {
'content-type': 'application/json',
},
})
}
// POST保存设置
if (request.method === 'POST') {
const body = await request.json()
const settings = body
// 兼容旧前端包:如果旧包尚未提交 webdav 配置,保留已有 WebDAV 渠道,避免保存其他上传设置时被清空。
if (settings.webdav === undefined) {
const existingSettingsStr = await db.get('manage@sysConfig@upload')
const existingSettings = existingSettingsStr ? JSON.parse(existingSettingsStr) : {}
if (existingSettings.webdav !== undefined) {
settings.webdav = existingSettings.webdav
}
}
// 写入数据库
await db.put('manage@sysConfig@upload', JSON.stringify(settings))
return new Response(JSON.stringify(settings), {
headers: {
'content-type': 'application/json',
},
})
}
}
export async function getUploadConfig(db, env) {
const settings = {}
// 读取数据库中的设置
const settingsStr = await db.get('manage@sysConfig@upload')
const settingsKV = settingsStr ? JSON.parse(settingsStr) : {}
// =====================读取tg渠道配置=====================
const telegram = {}
const telegramChannels = []
telegram.channels = telegramChannels
if (env.TG_BOT_TOKEN) {
telegramChannels.push({
id: 1,
name: 'Telegram_env',
type: 'telegram',
savePath: 'environment variable',
botToken: env.TG_BOT_TOKEN,
chatId: env.TG_CHAT_ID,
proxyUrl: env.TG_PROXY_URL || '', // 可选的代理 URL
enabled: true,
fixed: true,
})
}
for (const tg of settingsKV.telegram?.channels || []) {
// 如果savePath是environment variable,修改可变参数
if (tg.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (telegramChannels[0]) {
telegramChannels[0].enabled = tg.enabled
telegramChannels[0].proxyUrl = tg.proxyUrl
}
continue
}
// id自增
tg.id = telegramChannels.length + 1
telegramChannels.push(tg)
}
// 负载均衡
const tgLoadBalance = settingsKV.telegram?.loadBalance || {
enabled: false,
channels: [],
}
telegram.loadBalance = tgLoadBalance
// =====================读取r2渠道配置=====================
const cfr2 = {}
const cfr2Channels = []
cfr2.channels = cfr2Channels
if (env.img_r2) {
cfr2Channels.push({
id: 1,
name: 'R2_env',
type: 'cfr2',
savePath: 'environment variable',
publicUrl: env.R2PublicUrl,
enabled: true,
fixed: true,
})
}
for (const r2 of settingsKV.cfr2?.channels || []) {
// 如果savePath是environment variable,修改可变参数
if (r2.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (cfr2Channels[0]) {
cfr2Channels[0].publicUrl = r2.publicUrl
cfr2Channels[0].enabled = r2.enabled
cfr2Channels[0].quota = r2.quota // 保留容量限制配置
}
continue
}
// id自增
r2.id = cfr2Channels.length + 1
cfr2Channels.push(r2)
}
// 负载均衡
const r2LoadBalance = settingsKV.cfr2?.loadBalance || {
enabled: false,
channels: [],
}
cfr2.loadBalance = r2LoadBalance
// =====================读取s3渠道配置=====================
const s3 = {}
const s3Channels = []
s3.channels = s3Channels
if (env.S3_ACCESS_KEY_ID) {
s3Channels.push({
id: 1,
name: 'S3_env',
type: 's3',
savePath: 'environment variable',
accessKeyId: env.S3_ACCESS_KEY_ID,
secretAccessKey: env.S3_SECRET_ACCESS_KEY,
region: env.S3_REGION || 'auto',
bucketName: env.S3_BUCKET_NAME,
endpoint: env.S3_ENDPOINT,
pathStyle: env.S3_PATH_STYLE === 'true',
cdnDomain: env.S3_CDN_DOMAIN || '', // 可选的 CDN 域名
enabled: true,
fixed: true,
})
}
for (const s of settingsKV.s3?.channels || []) {
// 如果savePath是environment variable,修改可变参数
if (s.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (s3Channels[0]) {
s3Channels[0].enabled = s.enabled
s3Channels[0].quota = s.quota // 保留容量限制配置
s3Channels[0].cdnDomain = s.cdnDomain // 保留 CDN 域名配置
}
continue
}
// id自增
s.id = s3Channels.length + 1
s3Channels.push(s)
}
// 负载均衡
const s3LoadBalance = settingsKV.s3?.loadBalance || {
enabled: false,
channels: [],
}
s3.loadBalance = s3LoadBalance
// =====================读取 Discord 渠道配置=====================
const discord = {}
const discordChannels = []
discord.channels = discordChannels
// 从环境变量读取 Discord 配置
if (env.DISCORD_BOT_TOKEN) {
discordChannels.push({
id: 1,
name: 'Discord_env',
type: 'discord',
savePath: 'environment variable',
botToken: env.DISCORD_BOT_TOKEN,
channelId: env.DISCORD_CHANNEL_ID,
proxyUrl: env.DISCORD_PROXY_URL || '', // 可选的代理 URL
isNitro: env.DISCORD_IS_NITRO === 'true', // Nitro 会员,支持 25MB
enabled: true,
fixed: true,
})
}
for (const dc of settingsKV.discord?.channels || []) {
// 如果 savePath 是 environment variable,修改可变参数
if (dc.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (discordChannels[0]) {
discordChannels[0].enabled = dc.enabled
discordChannels[0].proxyUrl = dc.proxyUrl
discordChannels[0].isNitro = dc.isNitro
}
continue
}
// id 自增
dc.id = discordChannels.length + 1
discordChannels.push(dc)
}
// 负载均衡
const discordLoadBalance = settingsKV.discord?.loadBalance || {
enabled: false,
channels: [],
}
discord.loadBalance = discordLoadBalance
// =====================读取 HuggingFace 渠道配置=====================
const huggingface = {}
const huggingfaceChannels = []
huggingface.channels = huggingfaceChannels
// 从环境变量读取 HuggingFace 配置
if (env.HF_TOKEN) {
huggingfaceChannels.push({
id: 1,
name: 'HuggingFace_env',
type: 'huggingface',
savePath: 'environment variable',
token: env.HF_TOKEN,
repo: env.HF_REPO,
isPrivate: env.HF_PRIVATE === 'true',
enabled: true,
fixed: true,
})
}
for (const hf of settingsKV.huggingface?.channels || []) {
// 如果 savePath 是 environment variable,修改可变参数
if (hf.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (huggingfaceChannels[0]) {
huggingfaceChannels[0].enabled = hf.enabled
huggingfaceChannels[0].isPrivate = hf.isPrivate
}
continue
}
// id 自增
hf.id = huggingfaceChannels.length + 1
huggingfaceChannels.push(hf)
}
// 负载均衡
const huggingfaceLoadBalance = settingsKV.huggingface?.loadBalance || {
enabled: false,
channels: [],
}
huggingface.loadBalance = huggingfaceLoadBalance
// =====================读取 WebDAV 渠道配置=====================
const webdav = {}
const webdavChannels = []
webdav.channels = webdavChannels
// 从环境变量读取 WebDAV 配置
if (env.WEBDAV_BASE_URL) {
webdavChannels.push({
id: 1,
name: 'WebDAV_env',
type: 'webdav',
savePath: 'environment variable',
baseUrl: env.WEBDAV_BASE_URL,
username: env.WEBDAV_USERNAME || '',
password: env.WEBDAV_PASSWORD || '',
publicUrl: env.WEBDAV_PUBLIC_URL || '',
headers: normalizeWebDAVHeaders(env.WEBDAV_HEADERS || {}),
createDirectory: env.WEBDAV_CREATE_DIRECTORY !== 'false',
enabled: true,
fixed: true,
})
}
for (const wd of settingsKV.webdav?.channels || []) {
// 如果 savePath 是 environment variable,修改可变参数
if (wd.savePath === 'environment variable') {
// 如果环境变量未删除,进行覆盖操作
if (webdavChannels[0]) {
webdavChannels[0].enabled = wd.enabled
webdavChannels[0].publicUrl = wd.publicUrl || webdavChannels[0].publicUrl
webdavChannels[0].headers = normalizeWebDAVHeaders(wd.headers || wd.customHeaders || webdavChannels[0].headers)
webdavChannels[0].createDirectory = wd.createDirectory !== false
webdavChannels[0].quota = wd.quota
}
continue
}
// id 自增
wd.id = webdavChannels.length + 1
wd.headers = normalizeWebDAVHeaders(wd.headers || wd.customHeaders || {})
wd.createDirectory = wd.createDirectory !== false
webdavChannels.push(wd)
}
// 负载均衡
const webdavLoadBalance = settingsKV.webdav?.loadBalance || {
enabled: false,
channels: [],
}
webdav.loadBalance = webdavLoadBalance
settings.telegram = telegram
settings.cfr2 = cfr2
settings.s3 = s3
settings.discord = discord
settings.huggingface = huggingface
settings.webdav = webdav
return settings;
}