233 lines
9.9 KiB
Markdown
233 lines
9.9 KiB
Markdown
# apsis-web
|
|
|
|
[简体中文](./README.zh.md) | English
|
|
|
|
The web service layer of ApsisRS. It presents the ApsisRS computational
|
|
kernels for commercial spaceflight and satellite internet systems in a
|
|
browser: the concept documentation, a knowledge graph, the interface
|
|
documentation extracted from the library source, and an online tool set that
|
|
runs the kernels on parameters the user supplies.
|
|
|
|
The service builds to a single binary that embeds every asset it serves. It
|
|
does not read a content directory or a frontend build at run time, and it
|
|
does not need either to be present next to the binary.
|
|
|
|
## What it serves
|
|
|
|
| Section | Content | Route prefix |
|
|
|---------|---------|--------------|
|
|
| Concepts | Documents on the time scales, the reference frames, the element formats, and the propagation models, with the units and the applicable range of each | `/api/docs` |
|
|
| Knowledge graph | The concepts and their relationships, plus the crate structure of the library and the algorithm flow graphs | `/api/graph` |
|
|
| Interface | The public interface of the ApsisRS layers the service builds against, extracted from the source doc comments | `/api/api` |
|
|
| Online tools | TLE parsing, SGP4 propagation, track sampling, time scale conversion, coordinate conversion, frame rotation, Keplerian conversion, and Hohmann transfer planning | `/api/tools` |
|
|
|
|
## Design constraints
|
|
|
|
The service follows the constraints of the workspace it belongs to.
|
|
|
|
- **One runtime dependency.** The only entry in `[dependencies]` is
|
|
`apsis-rs`, through a path dependency. The HTTP server, the JSON codec,
|
|
the router, the Markdown renderer, and the graph model are all written
|
|
against the standard library.
|
|
- **No `unsafe`.** The crate does not contain an unsafe block.
|
|
- **No panic in a request path.** A malformed request, a bad parameter, or
|
|
a failing computation produces a response, not a panic. The worker that
|
|
serves a request catches a panic in the handler as a final guard and
|
|
answers with a server error.
|
|
- **Self-contained comments.** Every comment explains the code, the
|
|
algorithm, the interface, or the project. No comment refers to a private
|
|
document, an instruction, or a plan.
|
|
|
|
## Building
|
|
|
|
The frontend must be built before the release binary so that its output can
|
|
be embedded. A release build does this automatically.
|
|
|
|
Every built asset carries a content hash in its name, so replacing the binary
|
|
replaces those names. A browser therefore cannot be holding a stale bundle:
|
|
the new bundle is requested under a URL it has never seen. The entry point
|
|
is served with `no-cache, must-revalidate`, and hashed assets with
|
|
`public, max-age=31536000, immutable`. The service registers no service
|
|
worker.
|
|
|
|
```sh
|
|
# Development: a debug build embeds whatever is in frontend/dist and does
|
|
# not run the frontend build.
|
|
cargo build
|
|
|
|
# Release: build.rs builds the frontend and embeds the result.
|
|
cargo build --release
|
|
```
|
|
|
|
The binary is at `target/release/apsis-web`.
|
|
|
|
Environment variables:
|
|
|
|
| Variable | Effect |
|
|
|----------|--------|
|
|
| `APSIS_WEB_HOST` | Interface to bind, default `127.0.0.1` |
|
|
| `APSIS_WEB_PORT` | Port to bind, default `8080` |
|
|
| `APSIS_WEB_ADDRESS` | Bind address as `HOST:PORT`, overriding the two above |
|
|
| `APSIS_WEB_WORKERS` | Worker threads, default 4 |
|
|
| `APSIS_WEB_SKIP_FRONTEND` | Set to `1` to skip the frontend build in a release build |
|
|
| `APSIS_WEB_FRONTEND_DIR` | Frontend directory, default `frontend` |
|
|
|
|
Command line options override the environment:
|
|
|
|
```sh
|
|
# Bind every interface on port 8080.
|
|
apsis-web --host 0.0.0.0 --port 8080
|
|
|
|
# The combined form is equivalent.
|
|
apsis-web --address 0.0.0.0:8080
|
|
```
|
|
|
|
`--host` and `--port` may be given together. `--address` cannot be combined
|
|
with either of them, because the order in which they would apply is not
|
|
defined. A host may be a literal address, an IPv6 literal in brackets, or a
|
|
name the operating system resolves.
|
|
|
|
### Language
|
|
|
|
The interface is bilingual and opens in Chinese. The reader switches to
|
|
English with the control in the top bar; the choice is stored in the browser
|
|
and applies to every page.
|
|
|
|
The backend carries every user facing string in both languages, so the switch
|
|
takes effect without a request. A concept document is written once in English
|
|
as `content/concepts/<id>.md` and translated as
|
|
`content/concepts/<id>.zh.md`. A document without a translation is shown in
|
|
English to every reader, with a note saying so.
|
|
|
|
## Running
|
|
|
|
```sh
|
|
./target/release/apsis-web --address 127.0.0.1:8080
|
|
```
|
|
|
|
Open `http://127.0.0.1:8080`. The JSON interfaces are available without the
|
|
frontend:
|
|
|
|
- `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`
|
|
|
|
A tool call takes a JSON object of parameters and returns a shaped result:
|
|
|
|
```sh
|
|
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}'
|
|
```
|
|
|
|
## Content layout
|
|
|
|
The content is a superset of what any one library implements. It has two
|
|
groups.
|
|
|
|
**概念 / Concepts** describes the field. The layers follow the ones the
|
|
library is built in, because that is the order a reader meets the subject:
|
|
|
|
| Layer | Subject |
|
|
|-------|---------|
|
|
| 导论 Introduction | Scope, organisation, and how to read a page |
|
|
| 基础层 Foundations | Units, dimensions, numerical method, error |
|
|
| 物理层 Physics | Time scales and reference frames, which are two unrelated subjects and are both held here |
|
|
| 轨道层 Orbit | Elements, element formats, perturbations, propagators, manoeuvres |
|
|
| 射频与传播 Radio and propagation | Doppler, link budgets, the medium, interference |
|
|
| 星座与网络 Constellation and network | Constellations, access, topology, handover, routing |
|
|
| 运行层 Operations | Telemetry, tracking, command, planning |
|
|
| 仿真层 Simulation | Scenarios, events, and what a result means |
|
|
|
|
**实现 / Implementation** describes what one particular library implements
|
|
of the above, including how it is organised and where its algorithms come
|
|
from. Keeping it separate is what makes the concept set independent: a page
|
|
about link budgets does not change when a library changes.
|
|
|
|
A document belongs to the layer named by the directory it is in, so adding a
|
|
document means creating it under its layer and listing it in
|
|
`chapters.json`.
|
|
|
|
## Regenerating the interface catalog
|
|
|
|
The interface documentation is generated from the ApsisRS sources rather than
|
|
written by hand. Run the extractor from this directory when the sources
|
|
change, then rebuild:
|
|
|
|
```sh
|
|
scripts/extract_api.sh
|
|
cargo build --release
|
|
```
|
|
|
|
The script reads the workspace at `../apsis-rs` by default; set
|
|
`APSIS_RS_WORKSPACE` to point at a checkout elsewhere. It requires Python 3.8
|
|
or later. The Rust build does not run it and does not depend on Python.
|
|
|
|
## Editing the content
|
|
|
|
| Path | Contents |
|
|
|------|----------|
|
|
| `content/concepts/chapters.json` | The groups, their layers, and the reading order, with bilingual titles |
|
|
| `content/concepts/<layer>/*.md` | Documents, one directory per layer; the directory gives the layer, the file name gives the identifier |
|
|
| `content/concepts/<layer>/*.zh.md` | Chinese translations, named for the file they translate |
|
|
| `content/graph/concepts.json` | The concept graph |
|
|
| `content/flows/*.json` | The algorithm flow graphs |
|
|
| `content/api.json` | The generated interface catalog; do not edit by hand |
|
|
| `content/api.zh.json` | Chinese translations of the crate summaries and item doc comments |
|
|
|
|
A document header declares `title`, `summary`, `tags`, and `prerequisites`.
|
|
The identifier and the layer are not declared: the identifier is the file
|
|
name and the layer is the directory, so the two cannot disagree with the
|
|
tree. A cross reference is written `[[id]]` or `[[id|label]]` and renders as
|
|
a link that the frontend routes without a page load.
|
|
|
|
## Layout
|
|
|
|
```text
|
|
apsis-web/
|
|
├── build.rs embed the frontend build and the text content
|
|
├── Cargo.toml one runtime dependency: apsis-rs
|
|
├── content/ authored documents, graphs, and generated catalog
|
|
│ └── concepts/<layer>/ documents, one directory per layer
|
|
├── frontend/ Svelte and TypeScript, built by Vite
|
|
│ ├── src/lib/ API client, router, components, formatting
|
|
│ ├── src/pages/ one component per route
|
|
│ └── dist/ build output, embedded by build.rs
|
|
├── scripts/extract_api.sh interface catalog generator
|
|
├── src/
|
|
│ ├── api/ the router and the JSON payloads
|
|
│ ├── docs/ content, Markdown, documents, interface catalog
|
|
│ ├── embedded/ access to the embedded frontend assets
|
|
│ ├── graph/ the knowledge graph and the flow graphs
|
|
│ ├── http/ request, response, and server
|
|
│ ├── tools/ the tool registry, the handlers, the result shape
|
|
│ ├── json.rs the JSON codec
|
|
│ ├── main.rs the process entry point
|
|
│ └── state.rs the parsed content, shared by every worker
|
|
└── tests/service.rs end to end tests against the built binary
|
|
```
|
|
|
|
## Testing
|
|
|
|
```sh
|
|
cargo test # unit tests and end to end tests
|
|
cargo clippy --all-targets
|
|
cargo fmt --check
|
|
cd frontend && npm run check
|
|
```
|
|
|
|
The end to end tests start the built binary on an ephemeral port and make
|
|
plain TCP requests against it.
|
|
|
|
## License
|
|
|
|
GNU General Public License, version 3 or later, and that alone. See
|
|
`LICENSE`.
|
|
|
|
The service depends on `apsis-rs`, which is offered under MIT or
|
|
Apache-2.0. Both of those permit redistribution inside a GPL work, so the
|
|
two are distributed together under these terms. No other licence is
|
|
offered for this service.
|