# การพัฒนา

> HTML: https://remote.ivjn.us/docs/th/development/

เอกสารนี้อธิบายวิธีสร้าง ทดสอบ และรัน exchange แบบโลคัลในที่เก็บนี้ ขั้นตอนการปรับใช้ ตารางฟิลด์โปรโตคอล และรายละเอียดการติดตั้งแพลตฟอร์มจะยังคงอยู่ในเอกสารเฉพาะที่ลิงก์ไว้ตอนท้าย

## ทูลเชน

เวิร์กสเปซใช้ Rust 2021 และต้องการ **Rust 1.88 หรือใหม่กว่า** เวอร์ชันนี้ถูกบันทึกไว้ในฟิลด์ `rust-version` ของรูท `Cargo.toml`

## พื้นที่ทำงานและไบนารี

เวิร์กสเปซ Rust มีสมาชิกเก้ารายการ ได้แก่ แปดรายการใน `crates/` และ SDK สำหรับส่วนขยายใน `sdk/extend/rust` ชนิดข้อมูลของโปรโตคอลกำหนดไว้ที่ `crates/proto` เพียงแห่งเดียว โดย `exchange`, `agent` และ `cli` ใช้ crate นี้ร่วมกัน ห้ามกำหนดโครงสร้างข้อความซ้ำในแต่ละส่วนที่เรียกใช้

| crate | เส้นทาง | เอาท์พุต |
|---|---|---|
| `proto` | `crates/proto` | ไลบรารี; ข้อความควบคุม เฟรมไบนารี และโครงสร้างข้อมูลที่ใช้ร่วมกันอยู่ที่นี่เท่านั้น |
| `exchange` | `crates/exchange` | ไบนารี `exchange` (แพ็กเกจเดียวกันและชื่อไบนารี) |
| `agent` | `crates/agent` | `remote-agent` ไบนารี่ |
| `cli` | `crates/cli` | `remote-cli` ไบนารี่ |
| `updater` | `crates/updater` | ไลบรารีที่อัปเดตด้วยตนเองสำหรับ `remote-agent` และ `remote-cli` |
| `telemetry` | `crates/telemetry` | ข้อยกเว้นที่ใช้ร่วมกันและไลบรารีการรายงานบันทึกสำหรับทั้งสามองค์ประกอบ |
| `tls-client` | `crates/tls-client` | นโยบาย TLS ไคลเอ็นต์ rustlsที่ใช้ร่วมกันและการเชื่อมต่อพร็อกซีเสริม |
| `worker-proto` | `crates/worker-proto` | การตรวจสอบโปรโตคอลและการแฮชข้อมูลรับรองสำหรับ Workers Exchange |
| `remote-extend-sdk` | `sdk/extend/rust` | ไลบรารี; กรอบผู้ให้บริการส่วนขยายและสัญญา |

จุดเริ่มต้นสำหรับ `exchange` คือ `crates/exchange/src/main.rs` โดยไม่มีตาราง `[[bin]]` แยกต่างหาก ดังนั้น `cargo build -p exchange` จะสร้าง `exchange` รายการ `agent` และ `cli` (`Cargo.toml`) ตั้งชื่อไบนารีของตนอย่างชัดเจน `remote-agent` และ `remote-cli`

ตารางการเชื่อมต่อแบ่งตามความรับผิดชอบ:

- `crates/exchange/src/hub.rs` จัดการอุปกรณ์ออนไลน์ เชื่อมต่อการเปลี่ยนใหม่ และยุคสมัย
- `crates/exchange/src/hub/session_table.rs` แปล ID ฝั่งผู้ปฏิบัติงานและฝั่งอุปกรณ์
- `crates/exchange/src/hub/outbound.rs` จัดการคิวการส่งแบบมีขอบเขตสำหรับการเชื่อมต่อแต่ละรายการ

## สร้าง

รันคำสั่งเหล่านี้จากรูทของที่เก็บ

โปรไฟล์รีลีส (`opt-level = 2`, Thin LTO, Unwind ยังคงอยู่) สร้างเซิร์ฟเวอร์, CLI และ Agent:

```bash
cargo build --release
```

ไบนารีตั้งอยู่ที่:

- `target/release/exchange`
- `target/release/remote-cli`
- `target/release/remote-agent`

`release` ยังคงคลี่คลายเนื่องจาก exchange เป็นกระบวนการถาวรที่มีการเชื่อมต่อหลายรายการ หากงานการเชื่อมต่อเกิดความตื่นตระหนก การคลี่คลายจะทำให้ tokio หยุดงานนั้นโดยไม่ปิดเซสชันของอุปกรณ์อื่นในกระบวนการเดียวกัน

อุปกรณ์ Agent ยังมีโปรไฟล์ที่ปรับขนาดให้เหมาะสม (`opt-level = "z"`, LTO, `panic = "abort"`, `strip`, `codegen-units = 1`):

```bash
cargo build -p agent --no-default-features --profile release-small
```

เอาต์พุตคือ `target/release-small/remote-agent` เนื่องจาก procd, systemd หรือ Task Scheduler รีสตาร์ท Agent หลังจากเกิดข้อขัดข้อง โปรไฟล์นี้สามารถแลกเปลี่ยน `panic = "abort"` สำหรับไบนารีที่เล็กกว่าได้

ฐานข้อมูลไม่จำเป็นสำหรับการคอมไพล์ `crates/exchange/src/db.rs` ใช้คำสั่งรันไทม์ sqlx แทนที่จะเป็นมาโคร `query!` ดังนั้น `cargo build` จึงทำงานโดยไม่มีฐานข้อมูล

## การทดสอบ

```bash
cargo test --workspace
```

Windows ข้ามการทดสอบที่ต้องใช้ Unix `/bin/sh` (หรือ `/bin/ash` บน OpenWrt) และ PTY โมดูลทดสอบใน `crates/agent/src/pty.rs` ได้รับการปกป้องโดย `#[cfg(all(test, unix))]` และไม่ได้คอมไพล์บนแพลตฟอร์มที่ไม่ใช่ Unix การใช้งาน PTY จะพยายามใช้ `/bin/ash` จากนั้นจึงใช้ `/bin/sh` เส้นทางสัญญาณกลุ่มกระบวนการและ Unix ใน `exec.rs` ยังคอมไพล์บน Unix เท่านั้น การทดสอบคำสั่ง Windows ใช้ PowerShell โดยไม่ต้องเรียกใช้ `/bin/sh` หลังจากเปลี่ยนพาธ Unix ใน `exec.rs` หรือ `pty.rs` แล้ว ให้รัน `cargo test --workspace` บน Linux ด้วยเช่นกัน ผลลัพธ์ Windows เพียงอย่างเดียวไม่เพียงพอ

จำกัดขอบเขตให้เหลือเพียงลังเดียวเมื่อมีประโยชน์ เช่น `cargo test -p proto` หรือ `cargo test -p exchange -- hub::`

## รัน exchange ภายในเครื่อง

เตรียม PostgreSQL และใส่สตริงการเชื่อมต่อใน `DATABASE_URL` ตัวแปรนี้แม็พกับอ็อพชัน `exchange` `--database-url` (ดู `crates/exchange/src/config.rs`) เมื่อเริ่มต้น `db::connect` จะรันการย้ายข้อมูลแบบฝัง ณ เวลาคอมไพล์:

```rust
sqlx::migrate!("../../migrations")
```

ไฟล์การย้ายข้อมูลอยู่ในไดเรกทอรีรากของพื้นที่เก็บข้อมูล `migrations/` และทำงานโดยอัตโนมัติเมื่อเริ่มต้นระบบ sqlx-cli นั้นไม่จำเป็น

การใช้งานการตรวจสอบยังต้องใช้คีย์เข้ารหัสบันทึกการตรวจสอบ ตัวอย่างด้านล่างสร้างคีย์สำหรับทดสอบในเครื่อง ให้เก็บคีย์อย่างปลอดภัยและใช้คีย์เดิมในการเริ่มระบบครั้งถัดไป การสร้างคีย์ใหม่ทุกครั้งจะทำให้ถอดรหัสรายละเอียดการตรวจสอบเดิมไม่ได้

```bash
export DATABASE_URL='postgres://luci:luci@127.0.0.1:5432/luci'
export AUDIT_ENCRYPTION_KEY="$(python -c 'import base64, secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())')"
cargo run -p exchange -- --listen 127.0.0.1:8080
```

ใน PowerShell ให้ตั้งค่าตัวแปรสภาพแวดล้อมก่อน:

```powershell
$env:DATABASE_URL = "postgres://luci:luci@127.0.0.1:5432/luci"
$env:AUDIT_ENCRYPTION_KEY = python -c "import base64, secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())"
cargo run -p exchange -- --listen 127.0.0.1:8080
```

หากไบนารี่รีลีสถูกสร้างขึ้นแล้ว ให้แทนที่ `cargo run -p exchange --` ด้านบนด้วย `./target/release/exchange` ที่อยู่การฟังเริ่มต้นคือ `0.0.0.0:8080`; ผูกกับ `127.0.0.1` อย่างชัดเจนสำหรับการดีบักในเครื่อง

เมื่อฐานข้อมูลไม่มีบัญชีตัวดำเนินการที่เปิดใช้งาน การเริ่มต้นระบบจะบู๊ตผู้ดูแลระบบและพิมพ์โทเค็นในบันทึกการเริ่มต้นระบบนั้นเท่านั้น ข้อความธรรมดาปรากฏขึ้นหนึ่งครั้ง คำแนะนำในการปรับใช้ Reverse-proxy และบัญชีที่สมบูรณ์อยู่ในที่เก็บ `docs/deployment.md` หน้านั้นมีที่อยู่เซิร์ฟเวอร์และไม่ได้เผยแพร่บนเว็บไซต์นี้

## การตรวจสอบก่อนกระทำการ

รันการตรวจสอบเหล่านี้จากรูทของที่เก็บ สำหรับการเปลี่ยนแปลง Rust ให้เริ่มต้นด้วยการทดสอบลังแบบโฟกัส จากนั้นตรวจสอบพื้นที่ทำงานให้เสร็จสิ้น หากการตรวจสอบการจัดรูปแบบพบว่าการเลื่อนที่มีอยู่ไม่เกี่ยวข้อง ให้จัดรูปแบบเฉพาะไฟล์ที่เปลี่ยนแปลง แทนที่จะฟอร์แมตโค้ดอื่น Android ส่วนขยายเบราว์เซอร์และคอนโซลมือถือยังต้องมีการสร้างและการทดสอบของตัวเองด้วย การทดสอบ Rust ไม่ครอบคลุมพื้นผิวเหล่านั้น

```sh
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
```

## ดูแลรักษาเอกสาร

ตรวจสอบพฤติกรรมการใช้งานก่อนอัปเดตคำแนะนำที่เก็บข้อมูลใน `docs/` หัวข้อของเว็บไซต์มีแหล่งอ้างอิงที่ `website/docs/<topic>.md` และงานแปลเก้าฉบับที่ `website/docs/content/<locale>/<topic>.md` รักษาคำสั่ง ฟิลด์ ตัวอย่างโค้ด และระดับส่วนหัวให้สอดคล้องกัน สร้างหน้าและดัชนีการค้นหาด้วยสคริปต์ แทนที่จะแก้ไข HTML เพียงอย่างเดียว รันสิ่งต่อไปนี้จากรูทของที่เก็บโดยติดตั้ง Python 3.11+, markdown-it-py และ Node.js:

```sh
python -m pip install markdown-it-py
python scripts/build-docs.py
python scripts/build-docs.py --check
python scripts/test-docs.py
python scripts/test-docs-markdown.py
node scripts/test-docs-locale.js
python scripts/test-build-docs.py
python scripts/test-site-seo.py
```

การตรวจสอบการสร้างยังเปรียบเทียบทุกไบต์ของไฟล์ที่สร้างขึ้นด้วยไบต์ ความล้มเหลวในเอาต์พุตที่หายไปหรือเก่าโดยไม่ต้องเขียนไฟล์ CI รันมันก่อนที่จะสร้างใหม่

การตรวจสอบจะตรวจสอบความสมบูรณ์ของการแปล ตัวอย่างโค้ด โครงสร้างส่วนหัว ลิงก์หน้า จุดยึด และการกำหนดเส้นทางภาษา คอมมิตเพจที่สร้างขึ้นพร้อมแหล่งที่มา เอกสารประกอบอาคารเปลี่ยนแปลงไฟล์ในเครื่องเท่านั้น การใช้งานเว็บไซต์และสิ่งพิมพ์ดาวน์โหลดเป็นการดำเนินการที่แยกจากกัน

## เอกสารที่เกี่ยวข้อง

- [ภาพรวมทางเทคนิค](/docs/th/architecture.md): การเชื่อมต่อขาออก การแปลเซสชัน ยุค คิวที่มีขอบเขต และการจัดเก็บโทเค็น
- [Usage](/docs/th/getting-started.md): ล็อกอิน, การเพิ่มอุปกรณ์, การสตาร์ท Agent, คำสั่ง และเชลล์
- คู่มือการปรับใช้: พื้นที่เก็บข้อมูล `docs/deployment.md` (ประกอบด้วยที่อยู่เซิร์ฟเวอร์ ไม่ได้เผยแพร่บนเว็บไซต์นี้)
- [โปรโตคอลแบบใช้สาย](/docs/th/websocket-protocol.md)
- [การปรับใช้อุปกรณ์หลายแพลตฟอร์ม](/docs/th/platform-installation.md)
