Compare commits
No commits in common. "ed2b779d7bd855ef28404f2729812c5fa4b75177" and "e28e3493173657e2a857b113cb9c43de12920c59" have entirely different histories.
ed2b779d7b
...
e28e349317
|
|
@ -17,4 +17,4 @@
|
|||
|
||||
# Session exports dropped into the project directory by tooling that runs
|
||||
# alongside it. They are large and unrelated to the service.
|
||||
apsis-book.html
|
||||
apsis-web.html
|
||||
|
|
|
|||
|
|
@ -2,13 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "apsis-book"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"apsis-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "apsis-coord"
|
||||
version = "0.1.0"
|
||||
|
|
@ -132,3 +125,10 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"apsis-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "apsis-web"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"apsis-rs",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# apsis-book: the web service layer of ApsisRS.
|
||||
# apsis-web: the web service layer of ApsisRS.
|
||||
#
|
||||
# The service exposes the ApsisRS computational kernels over HTTP together
|
||||
# with the concept documentation, the knowledge graph, and the online tool
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
# together under these terms.
|
||||
|
||||
[package]
|
||||
name = "apsis-book"
|
||||
name = "apsis-web"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
|
|
@ -22,7 +22,7 @@ description = "Web service for the ApsisRS computational kernels."
|
|||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "apsis-book"
|
||||
name = "apsis-web"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
|||
24
README.md
24
README.md
|
|
@ -1,4 +1,4 @@
|
|||
# apsis-book
|
||||
# apsis-web
|
||||
|
||||
[简体中文](./README.zh.md) | English
|
||||
|
||||
|
|
@ -59,27 +59,27 @@ cargo build
|
|||
cargo build --release
|
||||
```
|
||||
|
||||
The binary is at `target/release/apsis-book`.
|
||||
The binary is at `target/release/apsis-web`.
|
||||
|
||||
Environment variables:
|
||||
|
||||
| Variable | Effect |
|
||||
|----------|--------|
|
||||
| `APSIS_BOOK_HOST` | Interface to bind, default `127.0.0.1` |
|
||||
| `APSIS_BOOK_PORT` | Port to bind, default `8080` |
|
||||
| `APSIS_BOOK_ADDRESS` | Bind address as `HOST:PORT`, overriding the two above |
|
||||
| `APSIS_BOOK_WORKERS` | Worker threads, default 4 |
|
||||
| `APSIS_BOOK_SKIP_FRONTEND` | Set to `1` to skip the frontend build in a release build |
|
||||
| `APSIS_BOOK_FRONTEND_DIR` | Frontend directory, default `frontend` |
|
||||
| `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-book --host 0.0.0.0 --port 8080
|
||||
apsis-web --host 0.0.0.0 --port 8080
|
||||
|
||||
# The combined form is equivalent.
|
||||
apsis-book --address 0.0.0.0:8080
|
||||
apsis-web --address 0.0.0.0:8080
|
||||
```
|
||||
|
||||
`--host` and `--port` may be given together. `--address` cannot be combined
|
||||
|
|
@ -102,7 +102,7 @@ English to every reader, with a note saying so.
|
|||
## Running
|
||||
|
||||
```sh
|
||||
./target/release/apsis-book --address 127.0.0.1:8080
|
||||
./target/release/apsis-web --address 127.0.0.1:8080
|
||||
```
|
||||
|
||||
Open `http://127.0.0.1:8080`. The JSON interfaces are available without the
|
||||
|
|
@ -186,7 +186,7 @@ a link that the frontend routes without a page load.
|
|||
## Layout
|
||||
|
||||
```text
|
||||
apsis-book/
|
||||
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
|
||||
|
|
|
|||
24
README.zh.md
24
README.zh.md
|
|
@ -1,4 +1,4 @@
|
|||
# apsis-book
|
||||
# apsis-web
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
|
|
@ -49,27 +49,27 @@ cargo build
|
|||
cargo build --release
|
||||
```
|
||||
|
||||
二进制位于 `target/release/apsis-book`。
|
||||
二进制位于 `target/release/apsis-web`。
|
||||
|
||||
环境变量:
|
||||
|
||||
| 变量 | 作用 |
|
||||
|------|------|
|
||||
| `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` |
|
||||
| `APSIS_WEB_HOST` | 绑定的网络接口,默认 `127.0.0.1` |
|
||||
| `APSIS_WEB_PORT` | 绑定的端口,默认 `8080` |
|
||||
| `APSIS_WEB_ADDRESS` | 以 `HOST:PORT` 表示的绑定地址,覆盖上面两项 |
|
||||
| `APSIS_WEB_WORKERS` | 工作线程数,默认 4 |
|
||||
| `APSIS_WEB_SKIP_FRONTEND` | 设为 `1` 时在发布构建中跳过前端构建 |
|
||||
| `APSIS_WEB_FRONTEND_DIR` | 前端目录,默认 `frontend` |
|
||||
|
||||
命令行选项优先于环境变量:
|
||||
|
||||
```sh
|
||||
# 在 8080 端口绑定所有网络接口。
|
||||
apsis-book --host 0.0.0.0 --port 8080
|
||||
apsis-web --host 0.0.0.0 --port 8080
|
||||
|
||||
# 合并写法等价。
|
||||
apsis-book --address 0.0.0.0:8080
|
||||
apsis-web --address 0.0.0.0:8080
|
||||
```
|
||||
|
||||
`--host` 与 `--port` 可以同时给出。`--address` 不能与它们中的任何一个合用,
|
||||
|
|
@ -88,7 +88,7 @@ apsis-book --address 0.0.0.0:8080
|
|||
## 运行
|
||||
|
||||
```sh
|
||||
./target/release/apsis-book --address 127.0.0.1:8080
|
||||
./target/release/apsis-web --address 127.0.0.1:8080
|
||||
```
|
||||
|
||||
打开 `http://127.0.0.1:8080`。JSON 接口不依赖前端即可访问:
|
||||
|
|
@ -164,7 +164,7 @@ cargo build --release
|
|||
## 目录结构
|
||||
|
||||
```text
|
||||
apsis-book/
|
||||
apsis-web/
|
||||
├── build.rs 嵌入前端构建产物与文本内容
|
||||
├── Cargo.toml 一个运行时依赖:apsis-rs
|
||||
├── content/ 撰写的文档、图谱与生成的目录
|
||||
|
|
|
|||
34
build.rs
34
build.rs
|
|
@ -1,4 +1,4 @@
|
|||
//! Build script for `apsis-book`.
|
||||
//! Build script for `apsis-web`.
|
||||
//!
|
||||
//! The script has one job: turn the frontend build output into a Rust source
|
||||
//! file that embeds every asset in the binary. It never introduces a crate
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
//! - In a debug build the frontend is not rebuilt. The script scans
|
||||
//! whatever is already in `frontend/dist/` and embeds it.
|
||||
//! - In a release build the script runs the frontend build first, unless
|
||||
//! `APSIS_BOOK_SKIP_FRONTEND=1` is set. The frontend directory can be
|
||||
//! changed with `APSIS_BOOK_FRONTEND_DIR`.
|
||||
//! `APSIS_WEB_SKIP_FRONTEND=1` is set. The frontend directory can be
|
||||
//! changed with `APSIS_WEB_FRONTEND_DIR`.
|
||||
//! - When `frontend/dist/` is absent the script emits an empty asset table.
|
||||
//! The service then serves a built-in placeholder page, so a checkout
|
||||
//! without a frontend build still compiles and runs.
|
||||
|
|
@ -27,7 +27,7 @@ use std::process::Command;
|
|||
fn main() {
|
||||
let manifest_dir = PathBuf::from(env("CARGO_MANIFEST_DIR"));
|
||||
let out_dir = PathBuf::from(env("OUT_DIR"));
|
||||
let frontend_dir = std::env::var("APSIS_BOOK_FRONTEND_DIR")
|
||||
let frontend_dir = std::env::var("APSIS_WEB_FRONTEND_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| manifest_dir.join("frontend"));
|
||||
let dist_dir = frontend_dir.join("dist");
|
||||
|
|
@ -58,13 +58,13 @@ fn main() {
|
|||
// after a build that embedded nothing causes the next build to embed it.
|
||||
// Cargo accepts a path that does not exist yet.
|
||||
println!("cargo:rerun-if-changed={}", dist_dir.display());
|
||||
println!("cargo:rerun-if-env-changed=APSIS_BOOK_SKIP_FRONTEND");
|
||||
println!("cargo:rerun-if-env-changed=APSIS_BOOK_FRONTEND_DIR");
|
||||
println!("cargo:rerun-if-env-changed=APSIS_WEB_SKIP_FRONTEND");
|
||||
println!("cargo:rerun-if-env-changed=APSIS_WEB_FRONTEND_DIR");
|
||||
|
||||
let is_release = std::env::var("DEBUG")
|
||||
.map(|value| value == "false")
|
||||
.unwrap_or(false);
|
||||
let skip = std::env::var("APSIS_BOOK_SKIP_FRONTEND")
|
||||
let skip = std::env::var("APSIS_WEB_SKIP_FRONTEND")
|
||||
.map(|value| value == "1")
|
||||
.unwrap_or(false);
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ fn main() {
|
|||
build_frontend(&frontend_dir);
|
||||
} else {
|
||||
println!(
|
||||
"cargo:warning=apsis-book: no frontend/package.json, embedding whatever is in {}",
|
||||
"cargo:warning=apsis-web: no frontend/package.json, embedding whatever is in {}",
|
||||
dist_dir.display()
|
||||
);
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ fn main() {
|
|||
let assets = if dist_dir.is_dir() {
|
||||
collect(&dist_dir).unwrap_or_else(|error| {
|
||||
println!(
|
||||
"cargo:warning=apsis-book: cannot scan {}: {error}",
|
||||
"cargo:warning=apsis-web: cannot scan {}: {error}",
|
||||
dist_dir.display()
|
||||
);
|
||||
Vec::new()
|
||||
|
|
@ -93,7 +93,7 @@ fn main() {
|
|||
|
||||
if assets.is_empty() {
|
||||
println!(
|
||||
"cargo:warning=apsis-book: no frontend assets found in {}; the placeholder page will be served",
|
||||
"cargo:warning=apsis-web: no frontend assets found in {}; the placeholder page will be served",
|
||||
dist_dir.display()
|
||||
);
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ fn main() {
|
|||
let content = if content_dir.is_dir() {
|
||||
collect(&content_dir).unwrap_or_else(|error| {
|
||||
println!(
|
||||
"cargo:warning=apsis-book: cannot scan {}: {error}",
|
||||
"cargo:warning=apsis-web: cannot scan {}: {error}",
|
||||
content_dir.display()
|
||||
);
|
||||
Vec::new()
|
||||
|
|
@ -137,7 +137,7 @@ fn build_frontend(frontend_dir: &Path) {
|
|||
let npm = if cfg!(windows) { "npm.cmd" } else { "npm" };
|
||||
|
||||
if !frontend_dir.join("node_modules").is_dir() {
|
||||
println!("cargo:warning=apsis-book: installing frontend dependencies");
|
||||
println!("cargo:warning=apsis-web: installing frontend dependencies");
|
||||
match Command::new(npm)
|
||||
.args(["install", "--no-audit", "--no-fund"])
|
||||
.current_dir(frontend_dir)
|
||||
|
|
@ -145,18 +145,18 @@ fn build_frontend(frontend_dir: &Path) {
|
|||
{
|
||||
Ok(status) if status.success() => {}
|
||||
Ok(status) => println!(
|
||||
"cargo:warning=apsis-book: npm install exited with {status}; embedding the existing dist if any"
|
||||
"cargo:warning=apsis-web: npm install exited with {status}; embedding the existing dist if any"
|
||||
),
|
||||
Err(error) => {
|
||||
println!(
|
||||
"cargo:warning=apsis-book: cannot run npm ({error}); embedding the existing dist if any"
|
||||
"cargo:warning=apsis-web: cannot run npm ({error}); embedding the existing dist if any"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("cargo:warning=apsis-book: building the frontend");
|
||||
println!("cargo:warning=apsis-web: building the frontend");
|
||||
match Command::new(npm)
|
||||
.args(["run", "build"])
|
||||
.current_dir(frontend_dir)
|
||||
|
|
@ -164,10 +164,10 @@ fn build_frontend(frontend_dir: &Path) {
|
|||
{
|
||||
Ok(status) if status.success() => {}
|
||||
Ok(status) => println!(
|
||||
"cargo:warning=apsis-book: npm run build exited with {status}; embedding the existing dist if any"
|
||||
"cargo:warning=apsis-web: npm run build exited with {status}; embedding the existing dist if any"
|
||||
),
|
||||
Err(error) => println!(
|
||||
"cargo:warning=apsis-book: cannot run npm run build ({error}); embedding the existing dist if any"
|
||||
"cargo:warning=apsis-web: cannot run npm run build ({error}); embedding the existing dist if any"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# apsis-book design notes
|
||||
# apsis-web design notes
|
||||
|
||||
These notes explain the decisions behind the service. They are for someone
|
||||
reading the code, and they describe the design rather than a plan.
|
||||
|
|
@ -202,7 +202,7 @@ does not relink.
|
|||
`build.rs` runs the frontend build in a release profile and skips it in a
|
||||
debug profile. The split is deliberate: a debug build iterates on the backend
|
||||
and should not pay for a frontend build, while a release build should produce
|
||||
one binary with no further steps. `APSIS_BOOK_SKIP_FRONTEND=1` forces the skip
|
||||
one binary with no further steps. `APSIS_WEB_SKIP_FRONTEND=1` forces the skip
|
||||
in a release build. A frontend failure is reported as a warning and the last
|
||||
successful output is embedded, so a release build without network access
|
||||
still produces a binary.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# apsis-book 设计说明
|
||||
# apsis-web 设计说明
|
||||
|
||||
[English](./design.md) | 简体中文
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ props 的纯函数,并使图在测试或截图中可复现。
|
|||
|
||||
`build.rs` 在 release 配置下运行前端构建,在 debug 配置下跳过它。这一划分是刻意
|
||||
的:调试构建迭代的是后端,不应为前端构建付出代价;发布构建则应当产出无需后续
|
||||
步骤的单一二进制。`APSIS_BOOK_SKIP_FRONTEND=1` 强制在发布构建中跳过。前端构建
|
||||
步骤的单一二进制。`APSIS_WEB_SKIP_FRONTEND=1` 强制在发布构建中跳过。前端构建
|
||||
失败会作为警告报告,并嵌入上一次成功的产物,因此在没有网络的情况下发布构建
|
||||
仍能产出二进制。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "apsis-book-frontend",
|
||||
"name": "apsis-web-frontend",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "apsis-book-frontend",
|
||||
"name": "apsis-web-frontend",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "apsis-book-frontend",
|
||||
"name": "apsis-web-frontend",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"description": "Frontend for the apsis-book service. Built output is embedded in the Rust binary.",
|
||||
"description": "Frontend for the apsis-web service. Built output is embedded in the Rust binary.",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export type Language = 'zh' | 'en';
|
|||
export const DEFAULT_LANGUAGE: Language = 'zh';
|
||||
|
||||
/** The key the choice is stored under. */
|
||||
const STORAGE_KEY = 'apsis-book-language';
|
||||
const STORAGE_KEY = 'apsis-web-language';
|
||||
|
||||
/** A string carried in both languages. */
|
||||
export interface Text {
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
The service presents the public interface of the `apsis-rs` workspace as it
|
||||
is written in the source, so the catalog is generated from the source rather
|
||||
than maintained by hand. This script reads the crate directories of the
|
||||
layers that `apsis-book` enables, collects the crate level documentation and
|
||||
layers that `apsis-web` enables, collects the crate level documentation and
|
||||
every public item with its doc comment and signature, and writes the result
|
||||
to `content/api.json`. The file is embedded in the binary by `build.rs`.
|
||||
|
||||
Run it from the `apsis-book` directory when the `apsis-rs` sources change:
|
||||
Run it from the `apsis-web` directory when the `apsis-rs` sources change:
|
||||
|
||||
scripts/extract_api.sh
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# `apsis-rs`. It is generated once and committed, so that building the Rust
|
||||
# binary does not depend on the apsis-rs checkout or on Python.
|
||||
#
|
||||
# Usage, from the apsis-book directory:
|
||||
# Usage, from the apsis-web directory:
|
||||
#
|
||||
# scripts/extract_api.sh
|
||||
#
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ impl Router {
|
|||
fn health(&self) -> Response {
|
||||
let body = json_object! {
|
||||
"status" => "ok",
|
||||
"service" => "apsis-book",
|
||||
"service" => "apsis-web",
|
||||
"version" => env!("CARGO_PKG_VERSION"),
|
||||
"documents" => self.state.docs.len(),
|
||||
"layers" => self
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl Server {
|
|||
let config = self.config;
|
||||
handles.push(
|
||||
thread::Builder::new()
|
||||
.name("apsis-book-worker".to_string())
|
||||
.name("apsis-web-worker".to_string())
|
||||
.spawn(move || worker_loop(&receiver, &*handler, config))?,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
57
src/main.rs
57
src/main.rs
|
|
@ -1,4 +1,4 @@
|
|||
//! The `apsis-book` service binary.
|
||||
//! The `apsis-web` service binary.
|
||||
//!
|
||||
//! The process binds an HTTP/1.1 listener and answers requests from three
|
||||
//! sources of content that are all embedded in the binary:
|
||||
|
|
@ -46,7 +46,7 @@ fn main() -> ExitCode {
|
|||
let options = match Options::from_environment() {
|
||||
Ok(options) => options,
|
||||
Err(message) => {
|
||||
eprintln!("apsis-book: {message}");
|
||||
eprintln!("apsis-web: {message}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
|
@ -61,7 +61,7 @@ fn main() -> ExitCode {
|
|||
let server = match Server::bind_address(options.address, config) {
|
||||
Ok(server) => server,
|
||||
Err(error) => {
|
||||
eprintln!("apsis-book: cannot bind {}: {error}", options.address);
|
||||
eprintln!("apsis-web: cannot bind {}: {error}", options.address);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
|
@ -70,15 +70,15 @@ fn main() -> ExitCode {
|
|||
.local_address()
|
||||
.map(|address| address.to_string())
|
||||
.unwrap_or_else(|_| options.address.to_string());
|
||||
println!("apsis-book listening on http://{bound}");
|
||||
println!("apsis-web listening on http://{bound}");
|
||||
if !embedded::is_populated() {
|
||||
println!("apsis-book: no frontend build is embedded; serving the placeholder page");
|
||||
println!("apsis-web: no frontend build is embedded; serving the placeholder page");
|
||||
}
|
||||
|
||||
match server.run(router) {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(error) => {
|
||||
eprintln!("apsis-book: server stopped: {error}");
|
||||
eprintln!("apsis-web: server stopped: {error}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
|
|
@ -95,8 +95,8 @@ struct Options {
|
|||
impl Options {
|
||||
/// Builds the options from the process arguments.
|
||||
///
|
||||
/// Arguments override the environment variables `APSIS_BOOK_HOST`,
|
||||
/// `APSIS_BOOK_PORT`, `APSIS_BOOK_ADDRESS`, and `APSIS_BOOK_WORKERS`.
|
||||
/// Arguments override the environment variables `APSIS_WEB_HOST`,
|
||||
/// `APSIS_WEB_PORT`, `APSIS_WEB_ADDRESS`, and `APSIS_WEB_WORKERS`.
|
||||
/// `--help` and `--version` print and exit.
|
||||
///
|
||||
/// The host and the port may be given separately with `--host` and
|
||||
|
|
@ -104,26 +104,25 @@ impl Options {
|
|||
/// either of the two separate options is an error, because the order in
|
||||
/// which they would apply is not defined.
|
||||
fn from_environment() -> Result<Self, String> {
|
||||
let mut host =
|
||||
std::env::var("APSIS_BOOK_HOST").unwrap_or_else(|_| DEFAULT_HOST.to_string());
|
||||
let mut port = match std::env::var("APSIS_BOOK_PORT") {
|
||||
Ok(value) => parse_port(&value).map_err(|error| format!("APSIS_BOOK_PORT: {error}"))?,
|
||||
let mut host = std::env::var("APSIS_WEB_HOST").unwrap_or_else(|_| DEFAULT_HOST.to_string());
|
||||
let mut port = match std::env::var("APSIS_WEB_PORT") {
|
||||
Ok(value) => parse_port(&value).map_err(|error| format!("APSIS_WEB_PORT: {error}"))?,
|
||||
Err(_) => DEFAULT_PORT,
|
||||
};
|
||||
let mut combined: Option<SocketAddr> = match std::env::var("APSIS_BOOK_ADDRESS") {
|
||||
Ok(value) => Some(
|
||||
parse_address(&value).map_err(|error| format!("APSIS_BOOK_ADDRESS: {error}"))?,
|
||||
),
|
||||
let mut combined: Option<SocketAddr> = match std::env::var("APSIS_WEB_ADDRESS") {
|
||||
Ok(value) => {
|
||||
Some(parse_address(&value).map_err(|error| format!("APSIS_WEB_ADDRESS: {error}"))?)
|
||||
}
|
||||
Err(_) => None,
|
||||
};
|
||||
let mut workers = match std::env::var("APSIS_BOOK_WORKERS") {
|
||||
let mut workers = match std::env::var("APSIS_WEB_WORKERS") {
|
||||
Ok(value) => value
|
||||
.parse()
|
||||
.map_err(|_| "APSIS_BOOK_WORKERS must be a positive integer".to_string())?,
|
||||
.map_err(|_| "APSIS_WEB_WORKERS must be a positive integer".to_string())?,
|
||||
Err(_) => 4,
|
||||
};
|
||||
if workers == 0 {
|
||||
return Err("APSIS_BOOK_WORKERS must be greater than zero".to_string());
|
||||
return Err("APSIS_WEB_WORKERS must be greater than zero".to_string());
|
||||
}
|
||||
|
||||
let mut host_given = false;
|
||||
|
|
@ -165,7 +164,7 @@ impl Options {
|
|||
std::process::exit(0);
|
||||
}
|
||||
"--version" | "-V" => {
|
||||
println!("apsis-book {}", env!("CARGO_PKG_VERSION"));
|
||||
println!("apsis-web {}", env!("CARGO_PKG_VERSION"));
|
||||
std::process::exit(0);
|
||||
}
|
||||
other => return Err(format!("unknown argument {other:?}; try --help")),
|
||||
|
|
@ -186,7 +185,7 @@ impl Options {
|
|||
} else if let Some(address) = combined {
|
||||
address
|
||||
} else {
|
||||
resolve(&host, port).map_err(|error| format!("APSIS_BOOK_HOST: {error}"))?
|
||||
resolve(&host, port).map_err(|error| format!("APSIS_WEB_HOST: {error}"))?
|
||||
};
|
||||
|
||||
Ok(Self { address, workers })
|
||||
|
|
@ -245,10 +244,10 @@ fn resolve(host: &str, port: u16) -> Result<SocketAddr, String> {
|
|||
|
||||
/// Usage text.
|
||||
const USAGE: &str = "\
|
||||
apsis-book: web service for the ApsisRS computational kernels
|
||||
apsis-web: web service for the ApsisRS computational kernels
|
||||
|
||||
USAGE:
|
||||
apsis-book [OPTIONS]
|
||||
apsis-web [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
-a, --address <HOST:PORT> address to bind (default 127.0.0.1:8080)
|
||||
|
|
@ -259,11 +258,11 @@ OPTIONS:
|
|||
-V, --version print the version
|
||||
|
||||
ENVIRONMENT:
|
||||
APSIS_BOOK_ADDRESS bind address, as HOST:PORT
|
||||
APSIS_BOOK_HOST interface to bind
|
||||
APSIS_BOOK_PORT port to bind
|
||||
APSIS_BOOK_WORKERS worker threads
|
||||
APSIS_WEB_ADDRESS bind address, as HOST:PORT
|
||||
APSIS_WEB_HOST interface to bind
|
||||
APSIS_WEB_PORT port to bind
|
||||
APSIS_WEB_WORKERS worker threads
|
||||
|
||||
EXAMPLES:
|
||||
apsis-book --host 0.0.0.0 --port 8080
|
||||
apsis-book --address 127.0.0.1:9000";
|
||||
apsis-web --host 0.0.0.0 --port 8080
|
||||
apsis-web --address 127.0.0.1:9000";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! exercises the request parser, the router, the JSON codec, the embedded
|
||||
//! content, and the tool handlers together, which the unit tests cannot do.
|
||||
//!
|
||||
//! The binary is located through the `CARGO_BIN_EXE_apsis-book` variable that
|
||||
//! The binary is located through the `CARGO_BIN_EXE_apsis-web` variable that
|
||||
//! cargo sets for an integration test, so the test always runs against the
|
||||
//! binary built from the same sources.
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ struct Service {
|
|||
impl Service {
|
||||
/// Starts the binary and waits for it to report its address.
|
||||
fn start() -> Self {
|
||||
let mut child = Command::new(env!("CARGO_BIN_EXE_apsis-book"))
|
||||
let mut child = Command::new(env!("CARGO_BIN_EXE_apsis-web"))
|
||||
.args(["--address", "127.0.0.1:0", "--workers", "2"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
|
|
|
|||
Loading…
Reference in New Issue