From 90e712373bedb7fae903102e7dea845168cfa536 Mon Sep 17 00:00:00 2001 From: Innei Date: Mon, 23 Jun 2025 12:04:19 +0800 Subject: [PATCH] refactor: remove deprecated storage functions and streamline storage management - Deleted the builder-storage.mdc file, which contained outdated documentation for the storage abstraction layer. - Removed deprecated functions related to S3 operations from the storage adapters, encouraging the use of the new StorageManager API. - Updated various components to utilize the StorageManager for file retrieval and URL generation, enhancing consistency and maintainability across the codebase. Signed-off-by: Innei --- .cursor/rules/builder-storage.mdc | 128 ------------------ .cursor/rules/i18n.mdc | 3 +- packages/builder/src/builder/builder.ts | 2 +- packages/builder/src/builder/index.ts | 2 +- packages/builder/src/index.ts | 11 +- packages/builder/src/photo/image-pipeline.ts | 10 +- .../builder/src/photo/live-photo-handler.ts | 6 +- packages/builder/src/storage/adapters.ts | 79 ----------- packages/builder/src/storage/factory.ts | 21 --- packages/builder/src/storage/index.ts | 2 +- packages/builder/src/storage/manager.ts | 9 +- 11 files changed, 19 insertions(+), 254 deletions(-) delete mode 100644 .cursor/rules/builder-storage.mdc delete mode 100644 packages/builder/src/storage/adapters.ts diff --git a/.cursor/rules/builder-storage.mdc b/.cursor/rules/builder-storage.mdc deleted file mode 100644 index e4021bc2..00000000 --- a/.cursor/rules/builder-storage.mdc +++ /dev/null @@ -1,128 +0,0 @@ ---- -description: -globs: -alwaysApply: false ---- -# 存储抽象层 - -本模块使用适配器模式提供了统一的存储接口,支持多种存储提供商。目前已实现 S3 存储提供商,后续可以方便地扩展其他存储服务。 - -## 架构设计 - -- **`interfaces.ts`**: 定义通用的存储接口和数据结构 -- **`providers/`**: 具体的存储提供商实现 - - **`s3-provider.ts`**: S3 存储提供商实现 -- **`factory.ts`**: 存储提供商工厂,负责创建具体的存储实例 -- **`manager.ts`**: 存储管理器,提供统一的存储操作接口 -- **`adapters.ts`**: 适配器函数,保持与原有 API 的兼容性 - -## 使用方式 - -### 推荐方式:使用 StorageManager - -```typescript -import { defaultStorageManager, StorageManager } from '@/core/storage' - -// 使用默认存储管理器(基于环境变量配置) -const buffer = await defaultStorageManager.getFile('path/to/image.jpg') -const images = await defaultStorageManager.listImages() -const allFiles = await defaultStorageManager.listAllFiles() -const publicUrl = defaultStorageManager.generatePublicUrl('path/to/image.jpg') -const livePhotos = await defaultStorageManager.detectLivePhotos() - -// 或者创建自定义配置的存储管理器 -const customManager = new StorageManager({ - provider: 's3', - bucket: 'my-bucket', - region: 'us-east-1', - endpoint: 'https://s3.amazonaws.com', - prefix: 'photos/', - customDomain: 'https://cdn.example.com' -}) -``` - -### 兼容性方式:使用原有 API - -```typescript -// 这些函数仍然可用,但标记为 deprecated -import { - getImageFromS3, - listImagesFromS3, - listAllFilesFromS3, - detectLivePhotos, - generateS3Url -} from '@/core/s3/operations' - -const buffer = await getImageFromS3('path/to/image.jpg') -const images = await listImagesFromS3() -``` - -### 直接使用存储提供商 - -```typescript -import { S3StorageProvider } from '@/core/storage' - -const s3Provider = new S3StorageProvider({ - provider: 's3', - bucket: 'my-bucket', - region: 'us-east-1', - // ... 其他配置 -}) - -const buffer = await s3Provider.getFile('path/to/image.jpg') -``` - -## 扩展新的存储提供商 - -1. 实现 `StorageProvider` 接口: - -```typescript -import { StorageProvider, StorageObject } from '@/core/storage/interfaces' - -export class MyStorageProvider implements StorageProvider { - async getFile(key: string, logger?: Logger['s3']): Promise { - // 实现文件获取逻辑 - } - - async listImages(): Promise { - // 实现图片列表逻辑 - } - - // ... 实现其他接口方法 -} -``` - -2. 在工厂类中注册新的提供商: - -```typescript -// 在 factory.ts 中添加新的 case -case 'my-storage': - return new MyStorageProvider(config) -``` - -3. 更新 `StorageConfig` 接口的 `provider` 类型。 - -## 优势 - -1. **解耦**: 业务逻辑与具体存储实现分离 -2. **可扩展**: 轻松添加新的存储提供商 -3. **统一接口**: 所有存储操作使用相同的 API -4. **向后兼容**: 保持原有 API 的兼容性 -5. **类型安全**: 完整的 TypeScript 类型支持 -6. **配置灵活**: 支持多种配置方式 - -## 迁移指南 - -现有代码可以继续使用原有的 S3 函数,无需立即修改。建议在新代码中使用 `StorageManager` API,并逐步迁移现有代码。 - -旧代码: -```typescript -import { getImageFromS3 } from '@/core/s3/operations' -const buffer = await getImageFromS3('key') -``` - -新代码: -```typescript -import { defaultStorageManager } from '@/core/storage' -const buffer = await defaultStorageManager.getFile('key') -``` \ No newline at end of file diff --git a/.cursor/rules/i18n.mdc b/.cursor/rules/i18n.mdc index ffc6c7fc..c58c237b 100644 --- a/.cursor/rules/i18n.mdc +++ b/.cursor/rules/i18n.mdc @@ -9,4 +9,5 @@ i18n 编写规范。 2. 使用扁平键。使用 `.` 方式分割。不能使用 object 形式嵌套。 3. 对单复数敏感的语言应该区分,使用 `_one` 和 `_other` 的形式。 4. 在 build 阶段,扁平化的点分隔键(如 'exif.custom.rendered.custom')会自动转换为嵌套的 object 对象,因此可能引发冲突。例如,'exif.custom.rendered.custom' 会与 'exif.custom.rendered' 发生冲突。请避免使用此类点分隔的扁平键。 -5. @locales 位于根目录,需要同时处理已有的全部的语言 \ No newline at end of file +5. @locales 位于根目录,需要同时处理已有的全部的语言 +6. 你需要修改 [en.json](mdc:locales/app/en.json) 然后再修改 [zh-CN.json](mdc:locales/app/zh-CN.json) 和其他语言。因为 eslint 会自动删除其他 json 中的 en 中没有的 key。 \ No newline at end of file diff --git a/packages/builder/src/builder/builder.ts b/packages/builder/src/builder/builder.ts index ce5ccfd7..ac8b7361 100644 --- a/packages/builder/src/builder/builder.ts +++ b/packages/builder/src/builder/builder.ts @@ -26,7 +26,7 @@ export interface BuilderOptions { concurrencyLimit?: number // 可选,如果未提供则使用配置文件中的默认值 } -export class PhotoGalleryBuilder { +class PhotoGalleryBuilder { private storageManager: StorageManager private config: BuilderConfig diff --git a/packages/builder/src/builder/index.ts b/packages/builder/src/builder/index.ts index f4058604..012d9124 100644 --- a/packages/builder/src/builder/index.ts +++ b/packages/builder/src/builder/index.ts @@ -1,2 +1,2 @@ export type { BuilderOptions } from './builder.js' -export { defaultBuilder, PhotoGalleryBuilder } from './builder.js' +export { defaultBuilder } from './builder.js' diff --git a/packages/builder/src/index.ts b/packages/builder/src/index.ts index ec04fe59..9bc394f5 100644 --- a/packages/builder/src/index.ts +++ b/packages/builder/src/index.ts @@ -1,9 +1,5 @@ // 主要构建器 -export { - type BuilderOptions, - defaultBuilder, - PhotoGalleryBuilder, -} from './builder/index.js' +export { type BuilderOptions, defaultBuilder } from './builder/index.js' export type { StorageConfig } from './storage/interfaces.js' // 日志系统 export { type Logger, logger, type WorkerLogger } from './logger/index.js' @@ -33,11 +29,6 @@ export { thumbnailExists, } from './image/thumbnail.js' export { s3Client } from './s3/client.js' -export { - generateS3Url, - getImageFromS3, - listImagesFromS3, -} from './s3/operations.js' // 照片处理 export { extractPhotoInfo } from './photo/info-extractor.js' diff --git a/packages/builder/src/photo/image-pipeline.ts b/packages/builder/src/photo/image-pipeline.ts index 2cb7ff8c..da56571a 100644 --- a/packages/builder/src/photo/image-pipeline.ts +++ b/packages/builder/src/photo/image-pipeline.ts @@ -1,13 +1,13 @@ import type { _Object } from '@aws-sdk/client-s3' import sharp from 'sharp' +import { defaultBuilder } from '../builder/builder.js' import { convertBmpToJpegSharpInstance, getImageMetadataWithSharp, isBitmap, preprocessImageBuffer, } from '../image/processor.js' -import { defaultStorageManager } from '../storage/manager.js' import type { PhotoManifestItem } from '../types/photo.js' import { processExifData, @@ -46,7 +46,9 @@ export async function preprocessImage( try { // 获取图片数据 - const rawImageBuffer = await defaultStorageManager.getFile(photoKey) + const rawImageBuffer = await defaultBuilder + .getStorageManager() + .getFile(photoKey) if (!rawImageBuffer) { loggers.image.error(`无法获取图片数据:${photoKey}`) return null @@ -199,7 +201,9 @@ export async function executePhotoProcessingPipeline( dateTaken: photoInfo.dateTaken, views: photoInfo.views, tags: photoInfo.tags, - originalUrl: defaultStorageManager.generatePublicUrl(photoKey), + originalUrl: defaultBuilder + .getStorageManager() + .generatePublicUrl(photoKey), thumbnailUrl: thumbnailResult.thumbnailUrl, blurhash: thumbnailResult.blurhash, width: metadata.width, diff --git a/packages/builder/src/photo/live-photo-handler.ts b/packages/builder/src/photo/live-photo-handler.ts index 2331cb3f..957cfc26 100644 --- a/packages/builder/src/photo/live-photo-handler.ts +++ b/packages/builder/src/photo/live-photo-handler.ts @@ -1,7 +1,7 @@ import type { _Object } from '@aws-sdk/client-s3' +import { defaultBuilder } from '../builder/builder.js' import type { StorageObject } from '../storage/interfaces.js' -import { defaultStorageManager } from '../storage/manager.js' import { getGlobalLoggers } from './logger-adapter.js' export interface LivePhotoResult { @@ -40,7 +40,9 @@ export function processLivePhoto( return { isLivePhoto: false } } - const livePhotoVideoUrl = defaultStorageManager.generatePublicUrl(videoKey) + const livePhotoVideoUrl = defaultBuilder + .getStorageManager() + .generatePublicUrl(videoKey) loggers.image.info(`📱 检测到 Live Photo:${photoKey} -> ${videoKey}`) diff --git a/packages/builder/src/storage/adapters.ts b/packages/builder/src/storage/adapters.ts deleted file mode 100644 index 006e90fc..00000000 --- a/packages/builder/src/storage/adapters.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { _Object } from '@aws-sdk/client-s3' - -import type { Logger } from '../logger/index.js' -import type { StorageObject } from './interfaces.js' -import { defaultStorageManager } from './manager.js' - -// 将 StorageObject 转换为 _Object 以保持兼容性 -function convertStorageObjectToS3Object(storageObject: StorageObject): _Object { - return { - Key: storageObject.key, - Size: storageObject.size, - LastModified: storageObject.lastModified, - ETag: storageObject.etag, - } -} - -/** - * 从 S3 获取图片(兼容性函数) - * @deprecated 推荐使用 defaultStorageManager.getFile() - */ -export async function getImageFromS3( - key: string, - s3Logger?: Logger['s3'], -): Promise { - return defaultStorageManager.getFile(key, s3Logger) -} - -/** - * 列出 S3 中的所有图片文件(兼容性函数) - * @deprecated 推荐使用 defaultStorageManager.listImages() - */ -export async function listImagesFromS3(): Promise<_Object[]> { - const storageObjects = await defaultStorageManager.listImages() - return storageObjects.map((obj) => convertStorageObjectToS3Object(obj)) -} - -/** - * 列出 S3 中的所有文件(兼容性函数) - * @deprecated 推荐使用 defaultStorageManager.listAllFiles() - */ -export async function listAllFilesFromS3(): Promise<_Object[]> { - const storageObjects = await defaultStorageManager.listAllFiles() - return storageObjects.map((obj) => convertStorageObjectToS3Object(obj)) -} - -/** - * 检测 live photo 配对(兼容性函数) - * @deprecated 推荐使用 defaultStorageManager.detectLivePhotos() - */ -export function detectLivePhotos(allObjects: _Object[]): Map { - // 转换 _Object 数组为 StorageObject 数组 - const storageObjects: StorageObject[] = allObjects.map((obj) => ({ - key: obj.Key || '', - size: obj.Size, - lastModified: obj.LastModified, - etag: obj.ETag, - })) - - // 使用存储管理器检测 Live Photos - const livePhotoMap = defaultStorageManager - .getProvider() - .detectLivePhotos(storageObjects) - - // 转换回 _Object 格式 - const result = new Map() - for (const [key, storageObject] of livePhotoMap) { - result.set(key, convertStorageObjectToS3Object(storageObject)) - } - - return result -} - -/** - * 生成 S3 公共 URL(兼容性函数) - * @deprecated 推荐使用 defaultStorageManager.generatePublicUrl() - */ -export function generateS3Url(key: string): string { - return defaultStorageManager.generatePublicUrl(key) -} diff --git a/packages/builder/src/storage/factory.ts b/packages/builder/src/storage/factory.ts index b2ff8acd..3fa0482f 100644 --- a/packages/builder/src/storage/factory.ts +++ b/packages/builder/src/storage/factory.ts @@ -1,5 +1,3 @@ -import { env } from '@env' - import type { StorageConfig, StorageProvider } from './interfaces' import { GitHubStorageProvider } from './providers/github-provider.js' import { S3StorageProvider } from './providers/s3-provider.js' @@ -20,23 +18,4 @@ export class StorageFactory { } } } - - /** - * 基于环境变量创建默认的存储提供商 - * @returns 默认存储提供商实例 - */ - static createDefaultProvider(): StorageProvider { - const config: StorageConfig = { - provider: 's3', - bucket: env.S3_BUCKET_NAME, - region: env.S3_REGION, - endpoint: env.S3_ENDPOINT, - accessKeyId: env.S3_ACCESS_KEY_ID, - secretAccessKey: env.S3_SECRET_ACCESS_KEY, - prefix: env.S3_PREFIX, - customDomain: env.S3_CUSTOM_DOMAIN, - } - - return this.createProvider(config) - } } diff --git a/packages/builder/src/storage/index.ts b/packages/builder/src/storage/index.ts index 9323310a..94ddd8b7 100644 --- a/packages/builder/src/storage/index.ts +++ b/packages/builder/src/storage/index.ts @@ -9,7 +9,7 @@ export type { export { StorageFactory } from './factory.js' // 导出管理器 -export { defaultStorageManager, StorageManager } from './manager.js' +export { StorageManager } from './manager.js' // 导出具体提供商(如果需要直接使用) export { GitHubStorageProvider } from './providers/github-provider.js' diff --git a/packages/builder/src/storage/manager.ts b/packages/builder/src/storage/manager.ts index 0a536f3c..54070df9 100644 --- a/packages/builder/src/storage/manager.ts +++ b/packages/builder/src/storage/manager.ts @@ -9,10 +9,8 @@ import type { export class StorageManager { private provider: StorageProvider - constructor(config?: StorageConfig) { - this.provider = config - ? StorageFactory.createProvider(config) - : StorageFactory.createDefaultProvider() + constructor(config: StorageConfig) { + this.provider = StorageFactory.createProvider(config) } /** @@ -78,6 +76,3 @@ export class StorageManager { this.provider = StorageFactory.createProvider(config) } } - -// 导出默认的存储管理器实例 -export const defaultStorageManager = new StorageManager()