apsis-book/README.zh.md

9.3 KiB
Raw Blame History

apsis-book

English | 简体中文

ApsisRS 的 Web 服务层。它在浏览器中呈现面向商业航天与卫星互联网的 ApsisRS 计算内核:概念文档、知识图谱、从库源码中提取的接口文档,以及一组 在线工具——用户给定参数,工具在这些内核上实际计算。

服务构建为单一二进制,其中嵌入了它所服务的全部资源。运行时不读取内容目录, 也不读取前端构建产物;二进制旁边不需要存在这两者。

服务内容

板块 内容 路由前缀
概念文档 关于时间尺度、参考系、元素格式、传播模型的文档,附各自的单位与适用范围 /api/docs
知识图谱 概念及其关系,以及库的 crate 结构与算法流程图 /api/graph
接口文档 服务所构建的 ApsisRS 各层的公共接口,从源码文档注释中提取 /api/api
在线工具 TLE 解析、SGP4 传播、轨迹采样、时间尺度换算、坐标换算、参考系旋转、开普勒换算与霍曼转移规划 /api/tools

设计约束

服务遵循它所属工作区的约束。

  • 一个运行时依赖。 [dependencies] 中只有 apsis-rs 一项,且是路径依赖。 HTTP 服务器、JSON 编解码器、路由器、Markdown 渲染器与图模型,全部基于标准库 编写。
  • 不使用 unsafe。 本 crate 不含任何 unsafe 代码块。
  • 请求路径中不 panic。 畸形请求、非法参数或计算失败都产生一个响应,而不是 panic。处理请求的工作线程会把处理函数中的 panic 捕获下来作为最后一道防线, 并返回服务器错误。
  • 注释自足。 每条注释都解释代码、算法、接口或项目本身;没有注释指向私有 文档、指令或计划。

构建

必须先构建前端,发布二进制才能嵌入其产物;发布构建会自动完成这一步。

每个构建出的资源,其文件名都带有内容哈希,因此替换二进制就替换了这些文件名。 浏览器因而不可能握着旧包:新包是在它从未见过的 URL 下请求的。入口页面以 no-cache, must-revalidate 提供,带哈希的资源则以 public, max-age=31536000, immutable 提供。服务不注册 service worker。

# 开发:调试构建嵌入 frontend/dist 中已有的内容,不运行前端构建。
cargo build

# 发布:build.rs 构建前端并嵌入结果。
cargo build --release

二进制位于 target/release/apsis-book。

环境变量:

变量 作用
APSIS_BOOK_HOST 绑定的网络接口,默认 127.0.0.1
APSIS_BOOK_PORT 绑定的端口,默认 8080
APSIS_BOOK_ADDRESS 以 HOST:PORT 表示的绑定地址,覆盖上面两项
APSIS_BOOK_WORKERS 工作线程数,默认 4
APSIS_BOOK_SKIP_FRONTEND 设为 1 时在发布构建中跳过前端构建
APSIS_BOOK_FRONTEND_DIR 前端目录,默认 frontend

命令行选项优先于环境变量:

# 在 8080 端口绑定所有网络接口。
apsis-book --host 0.0.0.0 --port 8080

# 合并写法等价。
apsis-book --address 0.0.0.0:8080

--host 与 --port 可以同时给出。--address 不能与它们中的任何一个合用, 因为二者生效的先后顺序没有定义。主机可以是字面地址、方括号中的 IPv6 字面量, 或由操作系统解析的名字。

语言

界面为双语,默认以中文打开。读者用顶栏中的控件切换到英文;该选择保存在浏览器 中,对所有页面生效。

后端为每一条面向读者的字符串同时保存两种语言,因此切换无需请求即可生效。 一篇概念文档的英文写为 content/concepts/<id>.md,中文译为 content/concepts/<id>.zh.md。没有译文的文档对所有读者显示英文,并附一条说明。

运行

./target/release/apsis-book --address 127.0.0.1:8080

打开 http://127.0.0.1:8080。JSON 接口不依赖前端即可访问:

  • GET /health
  • GET /api/docs、GET /api/docs/<id>、GET /api/docs/search?q=
  • GET /api/graph、GET /api/graph/crates、GET /api/graph/flows、GET /api/graph/<flow>
  • GET /api/api、GET /api/api/crates/<name>、GET /api/api/items/<name>
  • GET /api/tools、GET /api/tools/<id>、POST /api/tools/<id>/run

一次工具调用接受一个参数 JSON 对象,返回一个已整形的结果:

curl -s http://127.0.0.1:8080/api/tools/hohmann-transfer/run \
  -H 'content-type: application/json' \
  -d '{"from_radius": 6778, "to_radius": 42164}'

内容布局

内容是任何单一库所实现之物的一个超集,分为两组。

概念 / Concepts 描述这个领域。各层沿用库的分层,因为那是读者接触这个学科的 顺序:

层 主题
导论 范围、组织方式,以及如何阅读一页
基础层 单位、量纲、数值方法、误差
物理层 时间与坐标系是两个彼此无关的主题,故并列于此
轨道层 根数、元素格式、摄动、传播器、轨道机动
射频与传播 多普勒、链路预算、介质、干扰
星座与网络 星座、可见性、拓扑、切换、路由
运行层 遥测、跟踪、指令、规划
仿真层 场景、事件,以及结果的含义

实现 / Implementation 描述某一个特定的库对上述内容的实现情况,包括它如何 组织、以及它的算法从何而来。把它们分开,正是概念集保持独立的原因:一篇关于 链路预算的页面不会因为某个库变了而改变。

文档归属于它所在目录所命名的层,因此新增一篇文档就是在它所属的层下创建文件, 并在 chapters.json 中列出。

重新生成接口目录

接口文档由 ApsisRS 源码生成,而非手工撰写。那里的文档注释先写英文、再写中文, 提取器把两半拆开,因此两种语言都来自代码旁的同一段注释,谁也不会落后于它所描述的 代码。源码变化时在本目录运行提取脚本, 然后重新构建:

scripts/extract_api.sh
cargo build --release

脚本默认读取 ../apsis-rs 的工作区;设置 APSIS_RS_WORKSPACE 可指向别处的 检出。它需要 Python 3.8 或更高版本。Rust 构建不运行它,也不依赖 Python。

编辑内容

路径 内容
content/concepts/chapters.json 分组、各层与阅读顺序,含双语标题
content/concepts/<layer>/*.md 文档,每层一个目录;目录给出层,文件名给出标识
content/concepts/<layer>/*.zh.md 中文译文,文件名对应其所译的文件
content/graph/concepts.json 概念图谱
content/flows/*.json 算法流程图
content/api.json 生成的接口目录,含两种语言;不要手工编辑

文档头部声明 title、summary、tags 与 prerequisites。标识与层不由头部 声明:标识即文件名,层即目录,二者无法与目录结构相抵触。交叉引用写作 [[id]] 或 [[id|label]],渲染为链接,前端无须整页加载即可路由。

目录结构

apsis-book/
├── build.rs                  嵌入前端构建产物与文本内容
├── Cargo.toml                一个运行时依赖:apsis-rs
├── content/                  撰写的文档、图谱与生成的目录
│   └── concepts/<layer>/     文档,每层一个目录
├── frontend/                 Svelte 与 TypeScript,由 Vite 构建
│   ├── src/lib/              API 客户端、路由器、组件、格式化
│   ├── src/pages/            每个路由一个组件
│   └── dist/                 构建产物,由 build.rs 嵌入
├── scripts/extract_api.sh    接口目录生成器
├── src/
│   ├── api/                  路由器与 JSON 载荷
│   ├── docs/                 内容、Markdown、文档、接口目录
│   ├── embedded/             对嵌入式前端资源的访问
│   ├── graph/                知识图谱与流程图
│   ├── http/                 请求、响应与服务器
│   ├── tools/                工具注册表、处理函数、结果形状
│   ├── json.rs               JSON 编解码器
│   ├── lib.rs               各模块,以库的形式
│   ├── testkit.rs           测试所需的少数内部项
│   ├── main.rs               进程入口
│   └── state.rs              解析后的内容,供每个工作线程共享
└── tests/                   全部测试;`src/` 中没有
    ├── service.rs            针对构建出的二进制的端到端测试
    └── <module>.rs           各模块的测试

测试

cargo test          # 单元测试与端到端测试
cargo clippy --all-targets
cargo fmt --check
cd frontend && npm run check

端到端测试在一个临时端口上启动构建出的二进制,并以普通 TCP 请求与之通信。

许可协议

GNU 通用公共许可证,第 3 版或更高版本,且仅此一种。见 LICENSE。

本服务依赖 apsis-rs,后者以 MIT 或 Apache-2.0 提供。这两种协议都允许在 GPL 作品内再分发,因此二者可以按本协议一并分发。本服务不提供任何其他许可。