164 lines
5.6 KiB
TypeScript
164 lines
5.6 KiB
TypeScript
/**
|
||
* OSS存储适配器测试脚本
|
||
*
|
||
* 使用方法:
|
||
* 1. 配置环境变量(.env 文件)
|
||
* 2. 运行:npx tsx scripts/test-oss.ts
|
||
*
|
||
* 测试项:
|
||
* - 上传文件(按 MVP 目录结构)
|
||
* - 下载文件
|
||
* - 检查文件存在
|
||
* - 获取签名URL
|
||
* - 【可选】删除文件
|
||
*/
|
||
|
||
import dotenv from 'dotenv'
|
||
import path from 'path'
|
||
import fs from 'fs'
|
||
import { fileURLToPath } from 'url'
|
||
import { randomUUID } from 'crypto'
|
||
|
||
const __filename = fileURLToPath(import.meta.url)
|
||
const __dirname = path.dirname(__filename)
|
||
|
||
// 加载环境变量
|
||
dotenv.config({ path: path.join(__dirname, '../.env') })
|
||
|
||
import { StorageFactory } from '../src/common/storage/StorageFactory.js'
|
||
|
||
/**
|
||
* 生成存储 Key(按 MVP 目录结构)
|
||
*
|
||
* 格式:tenants/{tenantId}/users/{userId}/{module}/{uuid}.{ext}
|
||
*/
|
||
function generateStorageKey(
|
||
tenantId: string,
|
||
userId: string | null,
|
||
module: string,
|
||
filename: string
|
||
): string {
|
||
const uuid = randomUUID().replace(/-/g, '').substring(0, 16)
|
||
const ext = path.extname(filename)
|
||
|
||
if (userId) {
|
||
// 用户私有数据
|
||
return `tenants/${tenantId}/users/${userId}/${module}/${uuid}${ext}`
|
||
} else {
|
||
// 租户共享数据
|
||
return `tenants/${tenantId}/shared/${module}/${uuid}${ext}`
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
console.log('='.repeat(60))
|
||
console.log('OSS 存储适配器测试 - MVP 目录结构验证')
|
||
console.log('='.repeat(60))
|
||
|
||
// 检查环境变量
|
||
const storageType = process.env.STORAGE_TYPE || 'local'
|
||
console.log(`\n📦 存储类型: ${storageType}`)
|
||
|
||
if (storageType === 'oss') {
|
||
console.log(` Region: ${process.env.OSS_REGION}`)
|
||
console.log(` Bucket: ${process.env.OSS_BUCKET}`)
|
||
console.log(` Internal: ${process.env.OSS_INTERNAL}`)
|
||
}
|
||
|
||
// 获取存储实例
|
||
const storage = StorageFactory.getInstance()
|
||
console.log(`\n✅ 存储实例创建成功`)
|
||
|
||
// ============================================================
|
||
// 测试文件:真实 PDF 文献
|
||
// ============================================================
|
||
const testPdfPath = path.join(__dirname, '../../docs/06-测试文档/Ihl 2011.pdf')
|
||
|
||
if (!fs.existsSync(testPdfPath)) {
|
||
console.error(`\n❌ 测试文件不存在: ${testPdfPath}`)
|
||
process.exit(1)
|
||
}
|
||
|
||
const pdfBuffer = fs.readFileSync(testPdfPath)
|
||
console.log(`\n📄 测试文件: Ihl 2011.pdf`)
|
||
console.log(` 大小: ${(pdfBuffer.length / 1024).toFixed(2)} KB`)
|
||
|
||
// ============================================================
|
||
// 按 MVP 目录结构生成 Key
|
||
// ============================================================
|
||
// 模拟:租户 yizhengxun,用户 test-user-001,模块 pkb
|
||
const tenantId = 'yizhengxun'
|
||
const userId = 'test-user-001'
|
||
const module = 'pkb'
|
||
|
||
const storageKey = generateStorageKey(tenantId, userId, module, 'Ihl 2011.pdf')
|
||
|
||
console.log(`\n📁 目录结构验证:`)
|
||
console.log(` 租户ID: ${tenantId}`)
|
||
console.log(` 用户ID: ${userId}`)
|
||
console.log(` 模块: ${module}`)
|
||
console.log(` 生成Key: ${storageKey}`)
|
||
|
||
try {
|
||
// 1. 上传测试
|
||
console.log(`\n📤 上传文件到 OSS...`)
|
||
const uploadUrl = await storage.upload(storageKey, pdfBuffer)
|
||
console.log(` ✅ 上传成功!`)
|
||
console.log(` 签名URL: ${uploadUrl.substring(0, 80)}...`)
|
||
|
||
// 2. 检查存在
|
||
console.log(`\n🔍 验证文件存在...`)
|
||
const exists = await storage.exists(storageKey)
|
||
console.log(` 存在: ${exists ? '✅ 是' : '❌ 否'}`)
|
||
|
||
// 3. 下载验证
|
||
console.log(`\n📥 下载验证...`)
|
||
const downloadBuffer = await storage.download(storageKey)
|
||
const sizeMatch = downloadBuffer.length === pdfBuffer.length
|
||
console.log(` 下载大小: ${(downloadBuffer.length / 1024).toFixed(2)} KB`)
|
||
console.log(` 大小匹配: ${sizeMatch ? '✅ 是' : '❌ 否'}`)
|
||
|
||
// 4. 获取URL(不带原始文件名)
|
||
console.log(`\n🔗 获取访问URL...`)
|
||
const url = storage.getUrl(storageKey)
|
||
console.log(` URL: ${url.substring(0, 80)}...`)
|
||
|
||
// 5. 获取URL(带原始文件名 - 下载时恢复文件名)
|
||
console.log(`\n📎 获取带原始文件名的URL...`)
|
||
// 类型断言访问 OSSAdapter 的 getSignedUrl 方法
|
||
const ossAdapter = storage as any
|
||
if (typeof ossAdapter.getSignedUrl === 'function') {
|
||
const urlWithFilename = ossAdapter.getSignedUrl(storageKey, 3600, 'Ihl 2011.pdf')
|
||
console.log(` 原始文件名: Ihl 2011.pdf`)
|
||
console.log(` URL: ${urlWithFilename.substring(0, 80)}...`)
|
||
console.log(` ✅ 下载此URL时,浏览器会保存为 "Ihl 2011.pdf"`)
|
||
}
|
||
|
||
// ============================================================
|
||
// 🔴 不删除文件!保留在 OSS 中供验证
|
||
// ============================================================
|
||
console.log(`\n⚠️ 文件已保留在 OSS 中,不删除!`)
|
||
console.log(` 请登录阿里云 OSS 控制台查看:`)
|
||
console.log(` https://oss.console.aliyun.com/bucket/oss-cn-beijing/ai-clinical-data-dev/object`)
|
||
console.log(`\n 文件路径: ${storageKey}`)
|
||
|
||
// 测试完成
|
||
console.log('\n' + '='.repeat(60))
|
||
console.log('🎉 测试完成!请到 OSS 控制台验证目录结构')
|
||
console.log('='.repeat(60))
|
||
|
||
// 输出完整信息供验证
|
||
console.log(`\n📋 验证信息:`)
|
||
console.log(` Bucket: ai-clinical-data-dev`)
|
||
console.log(` Key: ${storageKey}`)
|
||
console.log(` 预期目录: tenants/yizhengxun/users/test-user-001/pkb/`)
|
||
|
||
} catch (error) {
|
||
console.error('\n❌ 测试失败:', error)
|
||
process.exit(1)
|
||
}
|
||
}
|
||
|
||
// 运行测试
|
||
main().catch(console.error)
|