Files
CloudFlare-ImgBed/functions/utils/metadata/metadataView.js
T

134 lines
4.6 KiB
JavaScript

/**
* Metadata 管理端视图工具
* 负责生成管理端可展示的 metadata,过滤敏感字段并按当前渠道配置补齐派生字段
*/
import { findConfiguredChannel, loadChannelConfig } from './channelConfig.js';
import { stripConfigDerivedMetadata, stripSensitiveMetadata } from './metadataSecurity.js';
import { buildWebDAVUrl } from '../storage/webdavAPI.js';
/* ========== 主要函数 ========== */
// 创建复用的视图上下文,避免批量序列化时重复读取上传配置
export async function createMetadataViewContext(db, env) {
return {
db,
env,
uploadConfig: await loadChannelConfig(db, env, 'metadata view'),
};
}
// 构建管理端可见 metadata,过滤敏感字段并补齐可展示链接
export async function buildFileMetadataForManagement(db, env, metadata = {}, viewContext = null) {
const context = viewContext || await createMetadataViewContext(db, env);
const view = stripConfigDerivedMetadata(stripSensitiveMetadata(metadata));
// 管理端展示字段从当前渠道配置实时补齐,不依赖旧 metadata 中保存的派生值
enrichS3Metadata(context, metadata, view);
enrichHuggingFaceMetadata(context, metadata, view);
enrichWebDAVMetadata(context, metadata, view);
return view;
}
// 将文件记录序列化为管理端列表接口使用的安全结构
export async function serializeFileRecordForManagement(db, env, file, viewContext = null) {
return {
name: file.id || file.name,
metadata: await buildFileMetadataForManagement(db, env, file.metadata, viewContext),
};
}
/* ========== 关键函数 ========== */
// 根据当前 S3 渠道配置补齐访问位置和 CDN URL
function enrichS3Metadata(context, sourceMetadata, view) {
if (sourceMetadata?.Channel !== 'S3') return;
try {
const channel = findConfiguredChannel(context.uploadConfig, 's3', sourceMetadata);
if (!channel) return;
const credentials = {
endpoint: channel.endpoint,
region: channel.region || 'auto',
bucketName: channel.bucketName,
pathStyle: channel.pathStyle || false,
cdnDomain: channel.cdnDomain || '',
key: sourceMetadata.S3FileKey,
};
if (!credentials.key) return;
if (credentials.endpoint && credentials.bucketName) {
view.S3Location = buildS3Location(credentials, credentials.key);
}
if (credentials.cdnDomain) {
view.S3CdnFileUrl = buildCdnFileUrl(credentials.cdnDomain, credentials.key);
}
} catch (error) {
console.warn('Failed to enrich S3 metadata:', error.message);
}
}
// 根据当前 HuggingFace 渠道配置补齐文件访问 URL
function enrichHuggingFaceMetadata(context, sourceMetadata, view) {
if (sourceMetadata?.Channel !== 'HuggingFace') return;
try {
const channel = findConfiguredChannel(context.uploadConfig, 'huggingface', sourceMetadata);
if (!channel) return;
if (channel.repo && sourceMetadata.HfFilePath) {
view.HfFileUrl = `https://huggingface.co/datasets/${channel.repo}/resolve/main/${sourceMetadata.HfFilePath}`;
}
} catch (error) {
console.warn('Failed to enrich HuggingFace metadata:', error.message);
}
}
// 根据当前 WebDAV 渠道配置补齐公开访问 URL
function enrichWebDAVMetadata(context, sourceMetadata, view) {
if (sourceMetadata?.Channel !== 'WebDAV') return;
try {
const channel = findConfiguredChannel(context.uploadConfig, 'webdav', sourceMetadata);
if (!channel) return;
if (channel.publicUrl && sourceMetadata.WebDAVFilePath) {
view.WebDAVPublicUrl = buildWebDAVUrl(channel.publicUrl, sourceMetadata.WebDAVFilePath);
}
} catch (error) {
console.warn('Failed to enrich WebDAV metadata:', error.message);
}
}
/* ========== 工具函数 ========== */
// 构建 S3 对象的源站访问地址
export function buildS3Location(credentials, key) {
const endpointHost = stripEndpointProtocol(credentials.endpoint);
if (!endpointHost || !credentials.bucketName || !key) return '';
// 同时支持 path-style 与 virtual-hosted-style 两种 S3 访问形式
if (credentials.pathStyle) {
return `https://${endpointHost}/${credentials.bucketName}/${key}`;
}
return `https://${credentials.bucketName}.${endpointHost}/${key}`;
}
// 构建渠道 CDN 域名下的文件访问地址
export function buildCdnFileUrl(cdnDomain, key) {
if (!cdnDomain || !key) return '';
return `${String(cdnDomain).replace(/\/+$/, '')}/${key}`;
}
// 去掉 endpoint 的协议和尾部斜杠,便于拼接 S3 地址
function stripEndpointProtocol(endpoint) {
return String(endpoint || '')
.trim()
.replace(/^https?:\/\//i, '')
.replace(/\/+$/, '');
}