Files
NetMount/docs/P1_PLAN.md
VirtualHotBar b7d2b78e43 feat(repository): 实现数据访问抽象层并统一日志服务
- 完成 Repository 层实现,包括 BaseRepository、ConfigRepository、
  StorageRepository、MountRepository、TaskRepository
- 迁移所有 console.log/warn/error 到统一的 LoggerService
- 实现 MountRepository 的原子性更新逻辑,支持配置变更检测
- 实现 TaskRepository 的任务状态管理和生命周期控制
- 添加完整的单元测试覆盖 StorageManager、FileManager、
  TransferService 及各 Repository 模块
- 新增 CacheManager 的 localStorage 持久化功能
- 优化 ChunkTransferService 的并发控制和信号量实现
- 修复 MountRepository ID 生成逻辑中的特殊字符冲突问题
- 实现 TaskRepository.update 的真正就地更新而非删除重建
- 补充完整的类型定义文档和 JSDoc 注释
2026-04-07 00:31:16 +08:00

21 KiB
Raw Permalink Blame History

P1 中优先级实施计划

计划周期2周10个工作日
开始时间2026-03-27
目标完善Repository层、性能优化
预期成果:架构更完善、性能显著提升


一、总体目标

核心目标

  1. 完善Repository层新增MountRepository和TaskRepository
  2. 性能优化:大文件传输优化、缓存策略优化
  3. 测试补充Repository层测试覆盖率达到30%+

成功标准

  • 2个新Repository实现并通过测试
  • 大文件传输速度提升50%+
  • 缓存命中率提升至80%+
  • Repository层测试覆盖率≥30%
  • Lint零错误零警告

二、任务分解与时间估算

第一周Repository层扩展5天

Day 1-2MountRepository实现2天

Day 1设计与基础实现

  • 上午4h

    • 设计MountRepository接口0.5h
    • 定义MountEntity类型0.5h
    • 实现BaseRepository继承1h
    • 实现基础CRUD方法2h
  • 下午4h

    • 实现挂载相关方法2h
      • mountStorage() - 挂载存储
      • unmountStorage() - 卸载挂载
      • getMountStatus() - 获取挂载状态
    • 实现挂载列表管理1h
      • getActiveMounts() - 获取活跃挂载
      • getMountsByStorage() - 按存储过滤
    • 编写单元测试1h

Day 2高级功能与集成

  • 上午4h

    • 实现自动挂载逻辑2h
      • 启动时自动挂载
      • 挂载失败重试
      • 挂载状态监控
    • 实现挂载点管理1h
      • validateMountPoint() - 验证挂载点
      • cleanupStaleMounts() - 清理失效挂载
    • 集成到Service层1h
  • 下午4h

    • 编写集成测试2h
    • 更新ARCHITECTURE.md文档1h
    • Code Review与重构1h

交付物

  • src/repositories/mount/MountRepository.ts (~250行)
  • src/repositories/__tests__/MountRepository.test.ts (~150行)
  • 文档更新

Day 3-4TaskRepository实现2天

Day 3设计与基础实现

  • 上午4h

    • 设计TaskRepository接口0.5h
    • 定义TaskEntity类型0.5h
    • 实现BaseRepository继承1h
    • 实现基础CRUD方法2h
  • 下午4h

    • 实现任务执行方法2h
      • executeTask() - 执行任务
      • cancelTask() - 取消任务
      • getTaskStatus() - 获取任务状态
    • 实现任务调度1h
      • scheduleTask() - 调度任务
      • getScheduledTasks() - 获取调度任务
    • 编写单元测试1h

Day 4高级功能与集成

  • 上午4h

    • 实现任务队列管理2h
      • 任务优先级
      • 任务依赖
      • 并发控制
    • 实现任务历史记录1h
      • getTaskHistory() - 获取历史
      • cleanOldHistory() - 清理旧历史
    • 集成到Controller层1h
  • 下午4h

    • 编写集成测试2h
    • 更新架构文档1h
    • Code Review与重构1h

交付物

  • src/repositories/task/TaskRepository.ts (~280行)
  • src/repositories/__tests__/TaskRepository.test.ts (~180行)
  • 文档更新

Day 5Repository层测试与文档1天

  • 上午4h

    • 补充Repository层单元测试2h
      • ConfigRepository测试补充
      • StorageRepository测试补充
    • 编写Repository层集成测试2h
      • 端到端测试流程
      • Mock Tauri invoke
  • 下午4h

    • 完善Repository层文档2h
      • API文档JSDoc
      • 使用示例
    • 性能基准测试2h
      • 响应时间测试
      • 缓存命中率测试

交付物

  • Repository层测试覆盖率≥30%
  • 完整API文档
  • 性能基准报告

第二周性能优化5天

Day 6-7大文件传输优化2天

Day 6传输机制优化

  • 上午4h

    • 分析当前传输瓶颈1h
      • Profile现有代码
      • 识别性能热点
    • 实现分块传输3h
      // src/services/storage/TransferService.ts
      interface ChunkTransfer {
        chunkSize: number // 5MB
        parallelChunks: number // 3
        progressCallback: (progress: number) => void
      }
      
  • 下午4h

    • 实现断点续传2h
      • 文件分片记录
      • 传输进度持久化
      • 断点恢复逻辑
    • 实现传输队列2h
      • 并发控制
      • 优先级队列
      • 失败重试

Day 7传输性能测试

  • 上午4h

    • 实现传输监控2h
      • 实时速度统计
      • ETA计算
      • 资源占用监控
    • 编写传输测试2h
      • 小文件测试(<10MB
      • 中文件测试10-100MB
      • 大文件测试(>100MB
  • 下午4h

    • 性能对比测试2h
      • 优化前后对比
      • 不同大小文件测试
      • 并发传输测试
    • 优化调整2h
      • 调整chunk大小
      • 调整并发数
      • 内存占用优化

预期优化效果

  • 小文件传输速度提升20-30%
  • 大文件传输速度提升50-80%
  • 支持断点续传
  • 内存占用减少40%

交付物

  • src/services/storage/ChunkTransferService.ts (~300行)
  • src/utils/transfer/chunkManager.ts (~150行)
  • 性能测试报告

Day 8-9缓存策略优化2天

Day 8缓存架构设计

  • 上午4h

    • 设计多级缓存架构2h
      L1: 内存缓存(热点数据)- 1分钟
      L2: 本地缓存(常用数据)- 10分钟
      L3: 持久化缓存(配置数据)- 1小时
      
    • 实现CacheManager2h
      class CacheManager {
        private l1Cache: Map<string, CacheEntry>
        private l2Cache: LocalStorageCache
        private l3Cache: FileCache
      
        get<T>(key: string, level: CacheLevel): T | null
        set<T>(key: string, value: T, ttl: number, level: CacheLevel): void
        invalidate(pattern: string): void
      }
      
  • 下午4h

    • 实现智能缓存策略2h
      • LRU淘汰算法
      • 缓存预热
      • 缓存降级
    • 实现缓存监控2h
      • 命中率统计
      • 缓存大小监控
      • 过期清理

Day 9缓存应用与优化

  • 上午4h

    • 应用到Repository层2h
      • ConfigRepository缓存优化
      • StorageRepository缓存优化
      • MountRepository缓存优化
    • 应用到Service层2h
      • StorageManager缓存
      • FileManager缓存
      • TransferService缓存
  • 下午4h

    • 缓存性能测试2h
      • 命中率测试
      • 响应时间测试
      • 内存占用测试
    • 缓存优化调整2h
      • TTL调整
      • 缓存大小限制
      • 淘汰策略优化

预期优化效果

  • 缓存命中率60% → 85%
  • 平均响应时间降低50%
  • 内存占用控制在100MB以内

交付物

  • src/utils/cache/CacheManager.ts (~250行)
  • src/utils/cache/CacheLevel.ts (~100行)
  • 缓存性能报告

Day 10集成测试与文档1天

  • 上午4h

    • 端到端性能测试2h
      • 完整业务流程测试
      • 性能回归测试
      • 压力测试
    • 编写性能基准文档2h
      • 性能指标定义
      • 测试方法说明
      • 优化前后对比
  • 下午4h

    • 更新架构文档2h
      • Repository层完整说明
      • 性能优化方案
      • 最佳实践
    • 编写迁移指南2h
      • 如何使用新Repository
      • 如何使用缓存API
      • 性能优化建议

交付物

  • 完整性能测试报告
  • 更新的架构文档
  • 最佳实践指南

三、技术方案详细设计

3.1 MountRepository 设计

接口定义

// src/repositories/interfaces/IMountRepository.ts
export interface IMountRepository extends IRepository<MountEntity> {
  // 挂载操作
  mountStorage(storageName: string, mountPoint: string, options?: MountOptions): Promise<MountEntity>
  unmountStorage(mountId: string): Promise<boolean>
  getMountStatus(mountId: string): Promise<MountStatus>
  
  // 挂载列表
  getActiveMounts(): Promise<MountEntity[]>
  getMountsByStorage(storageName: string): Promise<MountEntity[]>
  
  // 挂载点管理
  validateMountPoint(mountPoint: string): Promise<boolean>
  cleanupStaleMounts(): Promise<number>
  
  // 自动挂载
  enableAutoMount(storageName: string): Promise<void>
  disableAutoMount(storageName: string): Promise<void>
}

export interface MountEntity {
  id: string
  storageName: string
  mountPoint: string
  status: 'mounting' | 'mounted' | 'error' | 'unmounted'
  createdAt: Date
  options?: MountOptions
}

export interface MountOptions {
  readonly?: boolean
  allowOther?: boolean
  vfsCacheMode?: 'off' | 'full' | 'writes'
  bufferSize?: string // '16M'
}

实现要点

// src/repositories/mount/MountRepository.ts
export class MountRepository extends BaseRepository<MountEntity> {
  // 重写基类方法
  async getAll(): Promise<MountEntity[]> {
    return this.invokeCommand<MountEntity[]>('get_mount_list')
  }
  
  // 挂载存储
  async mountStorage(
    storageName: string,
    mountPoint: string,
    options?: MountOptions
  ): Promise<MountEntity> {
    // 1. 验证挂载点
    const isValid = await this.validateMountPoint(mountPoint)
    if (!isValid) {
      throw new RepositoryError('Invalid mount point', ErrorCode.INVALID_DATA)
    }
    
    // 2. 执行挂载
    await this.invokeCommand('mount_storage', {
      storageName,
      mountPoint,
      options
    })
    
    // 3. 获取挂载状态
    const mount = await this.getByMountPoint(mountPoint)
    
    // 4. 触发变更事件
    this.notifyChange({
      type: 'create',
      id: mount.id,
      newData: mount,
      timestamp: new Date()
    })
    
    return mount
  }
  
  // 清理失效挂载
  async cleanupStaleMounts(): Promise<number> {
    const mounts = await this.getAll()
    let cleaned = 0
    
    for (const mount of mounts) {
      if (mount.status === 'error' || mount.status === 'unmounted') {
        await this.delete(mount.id)
        cleaned++
      }
    }
    
    return cleaned
  }
}

3.2 TaskRepository 设计

接口定义

// src/repositories/interfaces/ITaskRepository.ts
export interface ITaskRepository extends IRepository<TaskEntity> {
  // 任务执行
  executeTask(taskId: string): Promise<TaskResult>
  cancelTask(taskId: string): Promise<boolean>
  getTaskStatus(taskId: string): Promise<TaskStatus>
  
  // 任务调度
  scheduleTask(task: Partial<TaskEntity>, schedule: ScheduleConfig): Promise<TaskEntity>
  getScheduledTasks(): Promise<TaskEntity[]>
  
  // 任务历史
  getTaskHistory(limit?: number): Promise<TaskHistory[]>
  cleanOldHistory(beforeDays: number): Promise<number>
  
  // 任务队列
  getPendingTasks(): Promise<TaskEntity[]>
  getNextTask(): Promise<TaskEntity | null>
  updateTaskPriority(taskId: string, priority: number): Promise<void>
}

export interface TaskEntity {
  id: string
  name: string
  type: 'copy' | 'move' | 'sync' | 'delete'
  status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
  priority: number // 1-10, 10最高
  config: TaskConfig
  schedule?: ScheduleConfig
  progress?: TaskProgress
  createdAt: Date
  startedAt?: Date
  completedAt?: Date
}

export interface ScheduleConfig {
  mode: 'once' | 'interval' | 'cron'
  time?: Date
  interval?: number // 秒
  cron?: string
}

实现要点

// src/repositories/task/TaskRepository.ts
export class TaskRepository extends BaseRepository<TaskEntity> {
  // 执行任务
  async executeTask(taskId: string): Promise<TaskResult> {
    const task = await this.getById(taskId)
    if (!task) {
      throw new RepositoryError('Task not found', ErrorCode.NOT_FOUND)
    }
    
    // 更新状态
    await this.update(taskId, {
      status: 'running',
      startedAt: new Date()
    })
    
    try {
      // 调用任务执行器
      const result = await this.invokeCommand<TaskResult>('execute_task', {
        taskId,
        config: task.config
      })
      
      // 更新完成状态
      await this.update(taskId, {
        status: 'completed',
        completedAt: new Date(),
        progress: { percent: 100 }
      })
      
      return result
    } catch (error) {
      // 更新失败状态
      await this.update(taskId, {
        status: 'failed',
        completedAt: new Date()
      })
      throw error
    }
  }
  
  // 获取下一个待执行任务
  async getNextTask(): Promise<TaskEntity | null> {
    const pending = await this.getPendingTasks()
    
    // 按优先级排序
    pending.sort((a, b) => b.priority - a.priority)
    
    return pending[0] || null
  }
}

3.3 大文件传输优化

分块传输设计

// src/services/storage/ChunkTransferService.ts
export class ChunkTransferService {
  private readonly DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024 // 5MB
  private readonly MAX_PARALLEL_CHUNKS = 3
  
  async transferLargeFile(
    source: string,
    destination: string,
    fileSize: number,
    options?: TransferOptions
  ): Promise<TransferResult> {
    const chunkSize = options?.chunkSize || this.DEFAULT_CHUNK_SIZE
    const totalChunks = Math.ceil(fileSize / chunkSize)
    
    // 创建传输任务
    const transferId = await this.createTransferTask({
      source,
      destination,
      fileSize,
      chunkSize,
      totalChunks
    })
    
    try {
      // 分块传输
      for (let i = 0; i < totalChunks; i++) {
        await this.transferChunk(transferId, i, {
          onProgress: (progress) => {
            options?.onProgress?.({
              chunk: i,
              total: totalChunks,
              percent: (i / totalChunks) * 100
            })
          }
        })
      }
      
      // 合并文件块
      await this.mergeChunks(transferId)
      
      return { success: true, transferId }
    } catch (error) {
      // 记录失败位置,支持断点续传
      await this.recordFailure(transferId, error)
      throw error
    }
  }
  
  // 断点续传
  async resumeTransfer(transferId: string): Promise<TransferResult> {
    const task = await this.getTransferTask(transferId)
    const completedChunks = await this.getCompletedChunks(transferId)
    
    // 从断点继续
    for (let i = completedChunks; i < task.totalChunks; i++) {
      await this.transferChunk(transferId, i)
    }
    
    await this.mergeChunks(transferId)
    return { success: true, transferId }
  }
}

3.4 缓存策略设计

多级缓存架构

// src/utils/cache/CacheManager.ts
export class CacheManager {
  private l1Cache: Map<string, CacheEntry> = new Map()
  private l2Cache: LocalStorageCache
  private l3Cache: FileCache
  
  private readonly MAX_L1_SIZE = 100 // 最多100个条目
  private readonly MAX_L2_SIZE = 10 * 1024 * 1024 // 10MB
  private readonly MAX_L3_SIZE = 100 * 1024 * 1024 // 100MB
  
  async get<T>(key: string): Promise<T | null> {
    // L1缓存
    const l1Entry = this.l1Cache.get(key)
    if (l1Entry && !this.isExpired(l1Entry)) {
      l1Entry.lastAccess = Date.now()
      return l1Entry.value as T
    }
    
    // L2缓存
    const l2Entry = await this.l2Cache.get(key)
    if (l2Entry && !this.isExpired(l2Entry)) {
      // 提升到L1
      this.setL1(key, l2Entry.value, l2Entry.ttl)
      return l2Entry.value as T
    }
    
    // L3缓存
    const l3Entry = await this.l3Cache.get(key)
    if (l3Entry && !this.isExpired(l3Entry)) {
      // 提升到L1和L2
      this.setL1(key, l3Entry.value, l3Entry.ttl)
      await this.l2Cache.set(key, l3Entry.value, l3Entry.ttl)
      return l3Entry.value as T
    }
    
    return null
  }
  
  async set<T>(
    key: string,
    value: T,
    ttl: number,
    level: CacheLevel = 'L1'
  ): Promise<void> {
    const entry: CacheEntry = {
      value,
      ttl,
      createdAt: Date.now(),
      lastAccess: Date.now()
    }
    
    switch (level) {
      case 'L1':
        this.setL1(key, value, ttl)
        break
      case 'L2':
        await this.l2Cache.set(key, value, ttl)
        break
      case 'L3':
        await this.l3Cache.set(key, value, ttl)
        break
      case 'ALL':
        this.setL1(key, value, ttl)
        await this.l2Cache.set(key, value, ttl)
        await this.l3Cache.set(key, value, ttl)
        break
    }
  }
  
  // LRU淘汰
  private evictL1(): void {
    if (this.l1Cache.size < this.MAX_L1_SIZE) return
    
    // 找到最久未访问的条目
    let oldest: { key: string; lastAccess: number } | null = null
    for (const [key, entry] of this.l1Cache.entries()) {
      if (!oldest || entry.lastAccess < oldest.lastAccess) {
        oldest = { key, lastAccess: entry.lastAccess }
      }
    }
    
    if (oldest) {
      this.l1Cache.delete(oldest.key)
    }
  }
}

四、验收标准

4.1 功能验收

功能模块 验收标准 测试方法
MountRepository 所有CRUD方法正常工作
挂载/卸载功能正常
自动挂载生效
单元测试 + 集成测试
TaskRepository 任务执行正常
任务调度生效
历史记录可查询单元测试 + 集成测试
大文件传输 支持>1GB文件传输
断点续传功能正常
速度提升≥50%
性能测试
缓存优化 命中率≥85%
响应时间降低50%
内存占用<100MB
性能测试

4.2 性能指标

性能指标 优化前 目标 测试方法
小文件传输速度 基准值 +20-30% 对比测试
大文件传输速度 基准值 +50-80% 对比测试
缓存命中率 60% 85% 监控统计
平均响应时间 基准值 -50% 压测
内存占用 基准值 <100MB 监控

4.3 代码质量

质量指标 目标 验证方法
ESLint 0 errors, 0 warnings npm run lint
TypeScript 0 errors npm run typecheck
测试覆盖率 Repository层≥30% npm run test:coverage
文档完整性 所有公共API有JSDoc Code Review

五、风险评估与应对

5.1 技术风险

风险 影响 概率 应对措施
Tauri API限制 提前验证API可用性准备降级方案
缓存一致性问题 实现缓存失效机制,添加版本控制
并发冲突 使用乐观锁,添加重试机制
内存泄漏 严格测试,添加内存监控

5.2 进度风险

风险 影响 概率 应对措施
任务预估不足 预留20%缓冲时间
依赖问题 提前准备依赖项
测试发现重大问题 及时调整优先级

六、资源需求

6.1 人力资源

  • 开发1人 × 10天 = 10人天
  • 测试0.5人 × 3天 = 1.5人天
  • 文档0.3人 × 2天 = 0.6人天
  • Code Review0.2人 × 2天 = 0.4人天

6.2 测试环境

  • 开发环境本地Tauri环境
  • 测试数据:测试用云存储账号
  • 性能测试:大文件测试数据(>1GB

6.3 工具需求

  • 性能分析工具Chrome DevTools
  • 内存分析Memory Profiler
  • 测试框架Vitest
  • 文档工具JSDoc

七、交付清单

7.1 代码交付物

Repository层扩展

  • src/repositories/mount/MountRepository.ts
  • src/repositories/task/TaskRepository.ts
  • src/repositories/__tests__/MountRepository.test.ts
  • src/repositories/__tests__/TaskRepository.test.ts

性能优化

  • src/services/storage/ChunkTransferService.ts
  • src/utils/transfer/chunkManager.ts
  • src/utils/cache/CacheManager.ts
  • src/utils/cache/CacheLevel.ts

测试代码

  • src/services/storage/__tests__/ChunkTransferService.test.ts
  • src/utils/cache/__tests__/CacheManager.test.ts

7.2 文档交付物

  • 更新的架构文档ARCHITECTURE.md
  • Repository层API文档JSDoc
  • 性能测试报告
  • 最佳实践指南

7.3 测试报告

  • 单元测试报告
  • 集成测试报告
  • 性能测试报告
  • 内存泄漏检测报告

八、后续维护计划

8.1 监控指标

  • Repository层调用频率
  • 缓存命中率
  • 传输速度统计
  • 内存占用监控

8.2 优化方向

  • 引入Redis缓存可选
  • 实现分布式任务调度
  • 添加性能仪表盘
  • 自动化性能回归测试

九、总结

核心价值

  • 架构更完善Repository层扩展为3个数据访问更规范
  • 性能更优秀大文件传输速度提升50-80%缓存命中率提升至85%
  • 质量更可靠:测试覆盖率提升,文档更完善

预期成果

  • 新增代码:~1500行Repository + 性能优化)
  • 测试代码:~600行
  • 文档:~500行
  • 性能提升50%+
  • 测试覆盖率30%+

时间估算

  • 开发时间8天
  • 测试时间1天
  • 文档时间1天
  • 总计10个工作日

计划制定人AI Assistant
计划日期2026-03-26
计划版本v1.0
下次审查2026-03-28Day 2结束