v0.2.12
v0.2.12 —— 「取消」和「移除」两颗按钮下岗,删除任何时候都能点
先说结论:功能一个没少,反而少按一次。 以前想清掉一个正在跑的任务要「先取消、再删除」两步,现在直接点删除就行 —— 任何状态都受理。这正是 v0.2.11 发版说明里预告过的那件事:「下一版把取消和删除两个动作合并成一个」。
任务行的动作按钮从 7 颗减到 5 颗(说的是首页任务面板;/history 独立页一直只有删除一颗,没有变化)
- 没了的两颗:「取消 ✕」(原本只对进行中的任务显示)和 「移除 ✕」(原本只对失败的任务显示)。
- 留下的五颗:启动 / 暂停 / 恢复 / 预览 / 删除。
- 为什么不算丢功能:
- 「取消」的唯一实际用途就是给删除当前置步骤 —— 删除以前拒收正在跑的任务,你必须先把它停下来。现在删除自己会停:点下去行立刻消失,后台去收尾。这一步不需要你操心了。
- 「移除」只对失败的任务有效,而且它只是把那一行从眼前拿走,数据库里的记录原封不动,下次刷新还在。删除是真的删,覆盖面比它大。
删除的确认框从两个减到一个,删正在跑的任务会先给你一句明确的警告
- 以前点删除要连过两个框:先问「确定要删除这个任务吗?」,再问「清理下载产物」,第二个框的两颗按钮是「删除产物」和「保留产物」。第二个框问的是另一件事,可它的取消位(ESC、点空白处、左边那颗「保留产物」)看上去像在撤销整个删除 —— 实际上任务照删不误,区别只在产物删不删。现在只有一个框:任务删不删走「确定 / 取消」,产物删不删走框里的一个勾选框「同时删除磁盘上的下载产物」,默认不勾(跟以前按 ESC 的结果一致,保留产物)。取消、ESC、点空白处现在就是什么都不做,一个删除请求也不会发出去。
- 删的是还没跑完的任务时,确认框会说清楚你会失去什么,而且三种状态分开说,不含糊成一句通用的:正在运行的说「删除会立即停止它,已下载的进度不保留」;还在排队的说「尚未开始,删除会把它移出队列」;已暂停的说「还没结束,删除会直接终止它」。上一版这句话不需要,因为后端会用 400 把这类删除挡下来(你看到的是「删除失败」)—— 这一版删除不再拒收任何状态,那层拦阻没了,就得把话说在前面。
- 产物在后台清理时,界面会告诉你:勾了「同时删除磁盘上的下载产物」而删的又是正在跑的任务,产物得等工作线程收工才能删(见下一段)。以前这种情况界面只说一句「任务已删除」,你转头去文件管理器一看几十 GB 还在,分不清是该等还是该自己动手删。现在它会明说「任务已删除,磁盘产物正在后台清理」。
磁盘产物怎么清理:删的是正在跑的任务时,行先消失、文件后台删
- 任务没在跑:行和文件同步删完,跟以前一样。
- 任务正在跑:程序先给它发停止信号,然后立刻删掉记录、把界面上那行拿走并返回;等下载 / 切片线程真正退出后,后台线程再去删磁盘产物。之所以不能当场等,是因为拼接、DEM 合并、等高线 warp 这些 GDAL 阶段一跑就是几分钟到几十分钟,中途打不断 —— 当场等的话你的浏览器会一直转圈。
- 万一在后台收尾之前程序被强杀,产物目录名已经记在数据库的待删清单里,下次启动会自动补删。
升级影响:库里已有的「已取消」任务会变成「失败」(一次性,不可逆)
- 「已取消」这个状态随功能一起从状态机里删掉了。你的数据库里如果还有这类记录,升级后首次启动时会自动改成「失败」,并写一句说明性的失败原因:
此版本移除了「取消任务」,该任务原为已取消。 - 不做这次迁移的话,那些行在界面上会显示成一列「未知」。
- 这个动作是一次性的、不可逆的;在意的话升级前备份一下
data/map_downloader.db。
v0.2.11 里那两块「没有任何入口能触发」的准备代码,这一版通电了
- DEM 地形切片中途可停:上一版加了登记与停止信号,但没有任何按钮能用到它。现在删除一个正在切片的 DEM 任务,就会真的把它停下来。
- 「待删产物清单」表开始真的往里写:上一版只建了表、零写入。现在删一个正在跑、**且勾了「同时清理磁盘产物」**的任务,就会往里记一笔,作为后台清理的兜底线索。
底图换了一条路:不再由浏览器直连上游,改走服务端转发
- 以前地图底图是浏览器直接去上游取瓦片,两个坑:上游返回 4xx 时错误页不带 CORS 头,浏览器把真实状态码(实测是 Esri 的 403)盖成一句 "blocked by CORS policy",看报错的人会去查一个根本不存在的 CORS 问题;更要命的是浏览器不吃配置页里的代理,底图和下载因此走两条出网路径——代理配好、瓦片哗哗下,底图照样可以是一个蓝色球体。
- 现在底图瓦片由后端转发(同源
/basemap/{z}/{x}/{y}),与下载共用同一套代理解析。配好一个,两个都通。 - 配置页新增「地图底图」一项:默认 Esri 卫星影像(国内直连可达),可选 Google 卫星 / 路网、「跟随下载源」,或自填一个
{z}/{x}/{y}模板。底图和下载源从此是两件事——底图决定你框选时看到什么,瓦片服务器列表决定你下载到什么。 - 预设只收 WGS-84 的源,不会有高德 / 腾讯:它们按 GCJ-02 切片,在国内偏移 100–700 米,底图上框住的山谷,下载下来是隔壁那个。
顺带一处界面变化
/history页的状态筛选里,「已取消」那枚筛选按钮跟着没了 —— 这个状态已经不存在,它永远筛不出任何一行。剩下「全部 / 进行中 / 失败 / 已完成」四枚。
这一版还修了一轮全项目评审查出来的问题(完整证据见 docs/reviews/2026-08-08-full-project-review.md)
先说三条会让你拿到错数据的:
- DEM 边界外那一圈「假地形」没了。 以前只要 DEM 的北边界或东边界正好压在瓦片格线上(1°×1° 的高程数据块几乎总是如此),每一级都会多出一整行/列瓦片;它们与真实数据零重叠,内容是把最边上一行像素向北抹平的一块台地,而且被声明成「可用」,Cesium 不会回落到底图。表现是:真实地形旁边贴着一块几十度宽的高原,HTTP 全 200、任务显示完成、日志一句报错都没有。
- 随包底图搬家不会再搬坏。 升级时底图缓存要从
downloads/挪到assets/(224 MB)。以前是直接往目标位置拷,跨盘时一旦中断(关机、磁盘满),目标位置会留下「有索引文件、没有瓦片」的半棵树 —— 而程序只看索引文件就判定底图可用,于是高程全错(实测把 4154 米读成 −744 米),并且这次迁移被记成已完成,永远不会重试。现在改成拷到临时名字、拷完才改名,中断就等于没搬,下次启动重新解压。 - 切片进度写库失败不再作废整个作业。 切片每秒往数据库记一次进度,这个写操作以前没有兜底:一次数据库锁冲突或磁盘写满,就会让一个已经跑了几小时、瓦片 99% 已经落盘的切片作业判失败,而切片没有断点续跑,重来要从最粗的层级全部重算。现在记账失败只写一行警告。
然后是任务卡住 / 状态说谎那一类:
- 任务不会再永久卡在「运行中」。 有两条路会留下「数据库说在跑、其实没有线程」的任务:一是启动时连不上数据库这类异常绕过了原有的兜底;二是删除任务时数据库提交失败,工作线程停下来了却没人改状态。卡住之后「开始」按钮会被拒(只接受待处理/已暂停),唯一的出路是先点一次「暂停」或者重启程序。现在线程退出时会自查一次,卡住的行直接判失败,可以重新开始。
- 暂停之后点「恢复」不会再报「已在运行」。 大区域拼接一跑十几分钟,中途打不断;这段时间界面显示「已暂停」,而每次点恢复都返回「任务已在运行」—— 两个互相矛盾的说法。现在这种情况会明确告诉你「上一轮还在收尾,请稍后重试」,而且拼接本身加了停止检查点,等待从「整个拼接」缩短到「当前这一张瓦片」。
- 删除任务不会再谎报「产物已删除」。 产物目录里只要有一个文件被别的程序占着(Windows 上资源管理器预览、杀毒扫描都会),以前接口照样回「已删除」,而整个瓦片金字塔还在盘上,且没有任何补删记录。现在如实回报,并登记下来,下次启动自动重试。
- 选「保留产物」不会再留下找不回来的目录。 删任务时如果选择保留磁盘产物,数据库里那行一走,产物目录就再没有任何引用,启动清扫也找不到它 —— 一个半成品切片目录(往往还带着一个与源数据同量级的中间文件)从此永久占着盘。现在会登记一条引用,响应里也直接告诉你保留在哪。
等高线:填错参数当场就说,不再让你白等几小时
- 颜色填成
#zzzzzz这种非法值,以前会一路通到渲染,然后每一张瓦片都失败,最后报一句「没有渲染出任何瓦片(请检查 DEM 覆盖 / 间距 / 缩放范围)」—— 指的三个参数全是对的。现在创建时就用渲染器自己的解析器校验,直接告诉你哪个字段的哪个值不对。 - 等高距填 0.1 米这种值,单张瓦片要画上万条线,而且瓦片画到一半既不能暂停也不能删。现在创建时就要求不小于 1 米。
凭据与配置
- NASA Earthdata 的账号密码不再出现在页面里。 以前配置页的密码框会把真实密码回填进 HTML,
GET /api/config也原样返回;同时首页把全部 45 个配置项(含密码和代理地址里的用户名密码)灌进一个页面级 JS 全局变量。现在密码框回填的是占位标记,接口也只回占位标记,页面里的 JS 变量只剩地图真正要用的 6 项。改密码、清空密码都照常。 - Earthdata 登录只会把密码发给 NASA 自己的域名。 以前判断「是不是跳到了 NASA 登录页」用的是子串匹配,
https://攻击者站点/?next=https://urs.earthdata.nasa.gov/...能骗过它。 - 配置里的路径和网址会被校验了。 以前除了十来个键,其余配置项(包括所有路径类和网址类)填什么都收。现在路径必须落在程序自己的目录范围内,网址必须是同源相对路径或正常的 http(s) 地址。
键盘和读屏
- 状态栏的「任务数」「光标坐标」「选区范围」三处以前只能用鼠标点(是
<span>不是按钮),键盘用户既打不开任务面板,也复制不了坐标。现在是真正的按钮。 - 状态筛选、主题、语言那几组分段按钮以前只用颜色表示选中,读屏软件读不出来;侧滑面板行为上是模态框却没有对应标记,Tab 会跑到被遮住的控件上。都补了。
给自己构建的人
./build.sh修好了。 它开头要检查 GDAL 版本,判据却是「requirements.txt 里有没有精确钉版本」—— 而那个文件里有一整段注释说明为什么不能精确钉。于是脚本在读取那一行时就静默退出,连准备好的报错都打不出来(set -euo pipefail让失败的 grep 直接终止脚本)。CI 走的是另一条命令,所以发版一直正常,没人发现。现在两个构建脚本共用scripts/check_gdal.py,判的是「装出来的版本落在声明范围内」加「_gdal_array在位」——后者才是真正会让所有高程/地形/等高线作业炸掉的那个坑,而它读版本号是读不出来的。- 单实例冲突提示改了。 以前它建议「确认上一个实例已崩溃就删掉锁文件」。锁锁的是文件本身而不是路径,删掉它只会让下一个实例新建一个文件再锁上 —— 两个实例同时认为自己独占,而第二个实例启动时的清扫会删掉第一个实例正在写的中间产物。锁在进程退出时由系统自动释放,本来就不需要手动删。
- 发布包里不再夹带冒烟测试留下的日志和半成品解压目录;Nuitka 与 matplotlib 钉了版本(前者用的是私有 API,上游一改签名就会在打完 tag 之后炸 Windows 构建);构建现在会校验
templates/和static/的关键文件真的进了产物(少了的话程序能启动、首页也 200,但地图是一片白,日志里什么都没有)。 - 多进程池在 Linux 上从 fork 改成 spawn,与 Windows / macOS 一致 —— 从多线程进程 fork 是 Python 3.12 起就在警告的用法,3.14 会改默认值。
| 变更 | 谁受影响 | 怎么改 |
|---|---|---|
四条 POST .../cancel 端点删除(/api/tasks/<id>/cancel、/api/dem/tasks/<id>/cancel、/api/contour/tasks/<id>/cancel、/api/terrain/local/tasks/<id>/cancel) |
调取消接口的脚本 | 改调对应的 DELETE(现在任何状态都能删);只想停不想删就用 pause |
失败的任务不能再重新开始(start 只收 pending / paused) |
直连 API 的脚本(界面上本来就没这个入口) | 删掉重建一个 |
四条管线的 DELETE 遇到正在跑的任务不再回 400,改为 200;同时要求清理磁盘产物时响应带 files_deferred: true(产物留给后台删) |
靠 400 判断「删不了」的脚本 | 看 files_deferred 决定要不要等产物清理 |
删除响应新增 files_deferred 字段;它为 true 时不下发 files_removed / files_message。没要求清理产物时这个字段根本不出现(delete_files 对地图 / 高程 / 等高线默认关,界面上选「保留产物」也走这条) |
解析删除响应的脚本 | 从三态处理改成四态处理,并按「键不存在」处理默认路径 |
本地地形 DELETE 找不到任务时从 400 改成 404 |
靠 400 判断的脚本 | 四条管线现在统一 404 |
GET /api/config 的 earthdata_password 回的是占位标记 __TF_UNCHANGED__,不再是真实密码 |
读这个接口取密码的脚本 | 拿不到真值了。把这个占位标记原样 PUT 回去等于「不修改」;要改就传新值,要清空就传空串 |
PUT /api/config 会拒收越界的路径类与网址类配置值(以前除十来个键之外一律照收) |
写配置的脚本 | 路径要落在程序目录范围内;terrain_base_parent_url 要么是同源相对路径,要么是正常 http(s) 地址 |
POST /api/contour/tasks:等高距小于 1 米、颜色值非法一律 400(以前收下、跑几小时后再失败) |
建等高线任务的脚本 | 按 400 里回的字段名和值改 |
等高线任务的 dataset 只接受 upload / dem_task;其它值(如 ASTGTM.003)会明确失败 |
直接往库里塞行或调老接口的脚本 | 先在「数据下载」里下 DEM,再基于那个 DEM 任务建等高线任务 |
删除响应在「保留产物」时新增 files_retained_path 字段 |
解析删除响应的脚本 | 可选:用它告诉用户产物留在哪 |
验证
- 本版全量测试 1757 项通过 / 3 项跳过(跳过的只在特定平台上有意义:Windows 文件锁、POSIX 专属的锁语义用例)。上一版是 1457 项。
- 上面「破坏性变更」各条都有常驻用例钉着(含一条反向断言:四条
/cancel路由不许重新出现在路由表里);「删正在跑的任务」四条管线另有各自的端到端用例。 - 这一轮评审修的每一条都做过变异校验:把实现换回旧写法,对应用例必须变红 —— 避免写出「怎么改都绿」的空断言。
通用说明
- 下载安装:从下方 Assets 下载对应平台压缩包(
terraforge-windows.zip/terraforge-linux.tar.gz/terraforge-macos.tar.gz),解压即用,无需安装 Python 环境。 - 下载体积:每个平台仍包含 167 MB 的全球底图分卷(自 v0.2.8 起)。
- 首次运行:启动可执行文件后,浏览器访问 http://localhost:5000 ;代理、并发、缓存管理等在「配置」页修改。
- 历史版本:完整更新历史见仓库 CHANGELOG.md。
- 使用文档:见仓库 README.md 与 docs/guides/QUICKSTART.md。