Ente Locker 回收站(Trash)完全指南:30 天保留、恢复与永久删除机制详解
【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente
在 Ente Locker 中删除条目时,数据并不会被立即抹除,而是先移入回收站(Trash),为你保留一段可反悔的缓冲期。本文以官方文档 trash.md 为核心,结合 Ente 服务端(Go)与客户端(Dart/Flutter)源码,完整讲解回收站的工作机制、删除/恢复/清空的完整操作流程,以及背后的数据库设计与定时清理原理。读完本文,你将掌握回收站的全部用法,并能从源码层面理解 30 天保留期是如何实现的。
回收站的核心机制
Ente Locker 的回收站遵循一套简单而严谨的"软删除 + 延迟硬删除"模型,核心规则如下:
- 删除即入站:删除条目后,它进入回收站而非立即消失,为误删提供安全网;
- 保留 30 天:回收站中的条目默认保留30 天;
- 到期永久删除:超过 30 天后,条目被服务端后台任务自动永久删除;
- 随时可恢复:在永久删除之前的任意时刻,你都可以把条目恢复到其原始收藏夹(collection);
- 支持手动清空:你可以手动清空回收站,让条目立即被永久删除。
这套机制的直观价值是:既避免了一键删除带来的不可逆损失,又通过明确的过期策略防止回收站无限膨胀。
删除条目(移入回收站)
在 Ente Locker 中删除一个条目的操作路径如下:
- 长按(Long press)你想要删除的条目;
- 点击出现的菜单图标;
- 选择Delete(删除);
- 确认删除。
条目随即被移入回收站。从客户端源码看,这一动作最终通过CollectionsService.trashFile构造一个TrashRequest(fileID, collectionID)请求,调用CollectionsApiClient.trash发送到服务端的POST /files/trash接口(见 collections_api_client.dart),随后触发本地回收站状态同步(TrashService.syncTrash)。
查看回收站
回收站视图的入口与操作如下:
- 在首页打开菜单;
- 点击Trash(回收站);
- 查看所有已删除条目及其删除日期。
客户端与服务端之间通过增量同步(diff sync)保持回收站状态一致:TrashService.syncTrash会拉取服务端GetDiff接口返回的回收站变更(新删除、已恢复、已永久删除的条目),并据此更新本地数据库(见 trash_service.dart)。也就是说,回收站列表不仅展示本地刚删除的条目,也会反映你在其他设备上执行的删除/恢复操作。
恢复条目(Restore)
恢复是回收站最重要的"后悔药"功能:
- 打开回收站(Trash);
- 点击要恢复的条目;
- 点击Restore(恢复);
- 条目回到其原始收藏夹。
在源码层面,恢复动作由TrashService.restore实现:客户端将待恢复文件的列表与目标收藏夹 ID 一起,通过POST /collections/restore-files提交给服务端(见 trash_service.dart)。恢复成功后,trash表中对应记录的is_restored标记会被置为true,该条目不再被视为待删除对象。
清空回收站
删除全部条目(Empty Trash)
- 打开回收站;
- 点击菜单图标;
- 选择Empty Trash(清空回收站);
- 确认永久删除。
[!WARNING] 清空回收站会永久删除其中所有条目,此操作不可撤销。
删除单个条目
- 打开回收站;
- 点击想要永久删除的条目;
- 点击Delete permanently(永久删除);
- 确认永久删除。
这里的关键差异在于:恢复(Restore)与永久删除(Delete permanently)是互斥的最终裁决。从服务端数据模型看,trash表对这两者施加了状态约束——is_deleted与is_restored不能同时为真(见 32_add_trash_table.up.sql),从而保证每条记录的状态语义唯一。
存储配额与回收站
需要特别留意:回收站中的条目仍然计入你的存储配额,直到它们被真正永久删除(无论是由 30 天到期自动触发,还是你手动清空)。
这意味着,仅靠"删除"并不能立刻释放存储空间。如果你迫切需要腾出配额,请主动清空回收站,或逐个执行"永久删除"。
服务端实现:回收站是如何工作的
Ente 的回收站并非简单的"延迟删除"标记,而是一套由数据库表、后台定时任务与任务队列协同运作的完整体系。以下从源码层面拆解其实现。
数据模型:trash表
回收站的核心数据模型定义在 trash.go,对应数据库表由迁移脚本 32_add_trash_table.up.sql 创建,关键字段如下:
| 字段 | 说明 |
|---|---|
file_id | 文件 ID,主键,外键关联collection_files |
user_id/collection_id | 所属用户与收藏夹 |
is_deleted | 是否已永久删除(无法再恢复) |
is_restored | 是否已被用户恢复 |
delete_by | 计划永久删除的时间戳,即"30 天后"的计算结果 |
created_at/updated_at | 创建与更新时间(微秒级) |
表上还建有updated_at索引(用于按时间分批处理)与delete_by索引(用于快速找出到期文件),见 34_trash_delete_by_idx.up.sql。
30 天保留期如何落地
"30 天"这一规则最终体现在delete_by字段上:条目进入回收站时,服务端会写入delete_by = 当前时间 + 30 天的时间戳。后台定时任务DeleteAgedTrashedFiles(见 trash.go 控制器)会定期执行:
- 通过分布式任务锁
DeleteAgedTrashedFiles确保同一时刻只有一个实例在跑; - 查询所有
delete_by <= 当前时间且is_deleted = false、is_restored = false的文件(见 repo/trash.go); - 按用户分组执行真正的永久删除(物理删除文件与记录)。
换句话说,只有既未恢复、又未删除的到期条目才会被物理清除——已恢复的条目会继续存在,已手动永久删除的条目则早已离开回收站。
清空与恢复的接口层
服务端为客户端提供了一组明确的回收站接口(见 trash.go 模型 与 trash.go 控制器):
- 删除条目:
DeleteTrashFilesRequest(携带fileIDs)→ 移入回收站; - 清空回收站:
EmptyTrashRequest要求客户端携带lastUpdatedAt时间戳——服务端只清空"该时间戳之前"的条目,避免后台排队中的任务误删刚刚新入站的条目; - 删除收藏夹:
TrashCollectionV3Request通过keepFiles布尔值决定是"仅删收藏夹、文件移入回收站"还是"连同文件一并处理"。
清空操作本身是异步的:接口先记录请求,随后由ProcessEmptyTrashRequests从任务队列中批量消费(区分 Photos 与 Locker 两个队列),并对每个用户/收藏夹加锁串行处理,防止并发冲突(见 trash.go 控制器)。
客户端视角:本地同步与离线一致性
在 Ente Locker 客户端中,回收站由TrashService统一管理,它在应用启动(main.dart中TrashService.instance.init)与每次删除/恢复/清空操作后自动触发syncTrash(),实现与服务端的增量同步(见 trash_service.dart)。同步内容包括:
- 新删除的条目(进入本地回收站视图);
- 已恢复的条目(从回收站视图移除并回到收藏夹);
- 已永久删除的条目(从回收站视图移除)。
本地数据库中还维护了一张trash_files表(见 locker_db.dart),使得回收站列表在离线状态下也能正常查看。
常见问题速查
以下问答同样收录于 FAQ 文档,与本文主题直接相关:
- 删除的条目在回收站保留多久?30 天,到期后自动永久删除(对应锚点 locker-trash-retention)。
- 30 天后还能找回吗?不能。30 天后条目被永久删除且无法恢复;若有保留需求,请在到期前恢复(对应锚点 locker-recover-after-30-days)。
- 回收站占用存储吗?占用。条目在被永久删除(到期自动删除或手动清空)之前,一直计入你的存储配额(对应锚点 locker-trash-storage)。
小结
Ente Locker 的回收站是一个典型的"软删除 + 延迟物理删除"设计:用户层面,它提供 30 天后悔期、随时恢复与手动清空三种能力;工程层面,它以trash表的delete_by时间戳为核心,配合后台定时任务、任务队列与分布式锁,可靠地完成到期清理与并发控制。理解这套机制,你既能更安全地管理自己的数据,也能举一反三地借鉴其实现思路。
【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考