# การอัปเดตอัตโนมัติ

> HTML: https://remote.ivjn.us/docs/th/self-update/

CLI และ Agent แบบสแตนด์อโลนสามารถอัปเดตปฏิบัติการของตนเองได้จากเว็บไซต์ที่เผยแพร่บน Windows x64/arm64, Linux x64/arm64 (บิลด์ glibc และ static musl), macOS Apple Silicon และ FreeBSD/NetBSD x64/arm64:

```sh
remote-cli update self --check
remote-cli update self
remote-agent update self --check
remote-agent update self
```

| แพลตฟอร์ม | เผยแพร่เอกสารสำคัญ | รีสตาร์ทหลังจาก `remote-agent update self` ยิงครั้งเดียว |
| --- | --- | --- |
| Windows x64 / arm64 | `remote-windows-x64.zip` / `remote-windows-arm64.zip` | งานที่กำหนดเวลาไว้ `RemoteAgent` จากนั้นดำเนินการรีสตาร์ท |
| Linux glibc x64 / arm64 | `remote-linux-x64.tar.gz` / `remote-linux-arm64.tar.gz` | systemd หรือหน่วยผู้ใช้ OpenRC จากนั้นให้รีสตาร์ทกระบวนการ |
| Linux มัสล์ x64 / arm64 | `remote-linux-musl-x64.tar.gz` / `remote-linux-musl-arm64.tar.gz` | เหมือนกับ Linux glibc |
| macOS แอปเปิ้ลซิลิคอน | `remote-macos-arm64.tar.gz` | LaunchAgent `us.ivjn.remote-agent` |
| FreeBSD / NetBSD x64 / arm64 | `remote-freebsd-*.tar.gz` / `remote-netbsd-*.tar.gz` | rc.d `remote_agent` จาก `remote-agent install --system`; มิฉะนั้นให้รีสตาร์ทด้วยตนเอง |

ตัวอัปเดตจะเก็บรันไทม์ C ของไฟล์ปฏิบัติการที่ทำงานอยู่: musl build จะติดตั้งเฉพาะไฟล์เก็บถาวร musl และ glibc build เฉพาะไฟล์เก็บถาวร glibc OpenWrt ยังคงอยู่บน opkg/apk แม้บน x64/arm64: แพ็คเกจของมันถูกสร้างขึ้นโดยไม่มีตัวอัปเดตไฟล์เก็บถาวร และ tarball musl ที่ทำงานบนโฮสต์ที่มี `/etc/openwrt_release` ปฏิเสธที่จะอัปเดตด้วยตนเอง แพลตฟอร์มจะอัปเดตเมื่อมีการจัดเก็บถาวรไว้ในรายการเท่านั้น การติดตั้งที่สร้างขึ้นก่อนที่จะรองรับแพลตฟอร์มนั้นจะต้องถูกเปลี่ยนด้วยตนเองหนึ่งครั้ง

ไม่จำเป็นต้องเข้าสู่ระบบบัญชีหรือกำหนดค่าอุปกรณ์

สำหรับการติดตั้ง Agent ครั้งแรก (ไบนารี + การกำหนดค่าส่วนตัว + การเริ่มต้นระบบปฏิบัติการอัตโนมัติ) แนะนำให้ใช้ `remote-agent install` / `remote-agent uninstall` บน Linux, macOS และ Windows — โปรดดูที่ [platforms.md](/docs/th/platform-installation.md) คำสั่งนั้นไม่จำเป็นต้องเข้าถึงเครือข่าย การจับคู่ยังคงแยกจากกัน หลังจากไบนารีที่รวม `install` อยู่บนเครื่องหนึ่งครั้ง การอัพเกรดในภายหลังสามารถใช้ `update self` หรืออัปเดตอัตโนมัติหากได้รับการสนับสนุน

`--check` เปรียบเทียบข้อมูลเมตา SHA-256 ที่ปฏิบัติการได้จากไฟล์ Manifest โดยไม่ต้องดาวน์โหลดไฟล์เก็บถาวร หากไม่มีข้อมูลเมตาที่ปฏิบัติการได้ ระบบจะดาวน์โหลดและตรวจสอบไฟล์เก็บถาวร การเปรียบเทียบแฮชจะแยกความแตกต่างระหว่างบิลด์การพัฒนาที่มีหมายเลขเวอร์ชันเดียวกัน การตรวจสอบไม่เคยเปลี่ยนแปลงการติดตั้ง การติดตั้งจะปฏิเสธการดาวน์เกรดและตรวจสอบเวอร์ชันที่ปฏิบัติการได้ ขนาด และแฮช

แหล่งที่มาเริ่มต้นคือ `https://r2.ivjn.us` (โดเมนสาธารณะ R2 ที่โฮสต์ `downloads/`) `--source https://your-mirror.example/releases` เลือกมิเรอร์ที่เชื่อถือได้ด้วย `downloads/manifest.json` และเค้าโครงไฟล์เก็บถาวรเดียวกัน GitHub Releases ([mbcc2006/remote-control releases](/#downloads)) เผยแพร่คลาสเดียวกันของไฟล์เก็บถาวรเดสก์ท็อปเป็นช่องดาวน์โหลด **เพิ่มเติม**; พวกเขาทำ **not** แทนที่เค้าโครงเว็บไซต์ และการอัปเดตด้วยตนเองยังคงใช้ `r2.ivjn.us` เว้นแต่คุณจะชี้ `--source` ไปที่มิเรอร์ที่ให้บริการ `downloads/manifest.json` ยอมรับเฉพาะ HTTPS เท่านั้น การเปลี่ยนเส้นทางถูกปฏิเสธ และไม่มีการส่งโทเค็นของบัญชี ชื่อไฟล์เก็บถาวรถูกเลือกจากระบบปฏิบัติการ/สถาปัตยกรรมปัจจุบัน ขนาดและ SHA-256 จะถูกตรวจสอบกับรายการ HTTPS และจะแยกเฉพาะรายการปฏิบัติการที่แน่นอนเท่านั้น ก่อนที่จะเชื่อถือไฟล์ Manifest ไคลเอ็นต์เดสก์ท็อปจะตรวจสอบ `downloads/manifest.json.sig` ด้วยพับลิกคีย์ Ed25519 ที่คอมไพล์แล้ว ลายเซ็นที่หายไป ไบต์ที่เปลี่ยนแปลง หรือคีย์ที่ไม่รู้จักจะปฏิเสธการอัปเดต กระจกเงาจะต้องแสดงเอกสารและรถเทียมข้างรถจักรยานยนต์ที่ลงนามไว้ทุกประการ เผยแพร่รถเทียมข้างรถจักรยานยนต์ก่อนที่จะเปิดตัวไคลเอนต์ที่ต้องการ

ก่อนการติดตั้ง ไฟล์ปฏิบัติการใหม่จะต้องผ่านการตรวจสอบ `--version` ที่มีขอบเขต การอัปเดตจะถูกทำให้เป็นอนุกรมโดยไฟล์ `.update.lock` ที่เป็นพี่น้องกัน และไฟล์ปฏิบัติการปัจจุบันจะถูกตรวจสอบอีกครั้งเพื่อตรวจหาการแทนที่พร้อมกัน การอัปเดตจะแตะเฉพาะไฟล์ปฏิบัติการและไฟล์อัปเดต/สำรองเท่านั้น ID อุปกรณ์ ข้อมูลประจำตัว และไฟล์การกำหนดค่าจะถูกเก็บรักษาไว้

บน macOS ไฟล์ปฏิบัติการที่ดาวน์โหลดจะต้องผ่าน `codesign --verify --strict` ก่อนที่จะตรวจสอบเวอร์ชัน ลายเซ็นและไบต์ที่เผยแพร่จะถูกเก็บรักษาไว้ในระหว่างการแทนที่ ดังนั้นการเปรียบเทียบแฮชที่ตามมาจึงยังคงมีเสถียรภาพ

ไฟล์เรียกทำงานก่อนหน้านี้จะคงไว้เป็น `<executable>.previous` หากจำเป็น ให้หยุด Agent และกู้คืนไฟล์นั้นไปยังพาธปฏิบัติการดั้งเดิม บน Windows ไฟล์เรียกทำงานที่โหลดจะถูกเปลี่ยนชื่อเป็นข้อมูลสำรองก่อนทำการติดตั้งตัวทดแทน ความล้มเหลวในการติดตั้งจะคืนค่าชื่อเดิม

หลังจาก `remote-agent update self` สำเร็จ (ไม่ใช่ `--check`) ตัวอัปเดตจะพยายามรีสตาร์ทการรัน Agent เพื่อโหลดไบนารีใหม่: บน Linux (glibc และ musl) ตัวอัปเดตจะรัน `systemctl restart remote-agent` จากนั้น `systemctl --user restart remote-agent` จากนั้น `rc-service remote-agent restart` เมื่อ มี `/etc/init.d/remote-agent` อยู่แล้ว (OpenRC) และหากสิ่งเหล่านั้นไม่พร้อมใช้งาน SIGTERM จะรีสตาร์ทกระบวนการ `remote-agent` daemon อื่นด้วยอาร์กิวเมนต์ก่อนหน้า บน Windows (x64 และ arm64) จะรีสตาร์ทงานที่กำหนดเวลาไว้ `RemoteAgent` พร้อมด้วยทางเลือกระดับกระบวนการ บน FreeBSD/NetBSD จะรันสคริปต์ rc.d `remote_agent restart` ที่ติดตั้งโดย `remote-agent install --system` และรายงานว่าจำเป็นต้องรีสตาร์ทด้วยตนเอง หากกระบวนการอัปเดตนั้นเป็น daemon (อาร์กิวเมนต์ไม่ใช่ `update self`) กระบวนการนั้น `exec` จะเป็นไบนารีใหม่บน Unix (รักษา PID ไว้สำหรับผู้บังคับบัญชา) หรือสร้างการแทนที่ที่แยกออกมาบน Windows `remote-cli update self` ไม่เคยรีสตาร์ท Agent บรรทัดสถานะจะรายงานว่ารีสตาร์ทที่ใช้ systemd, OpenRC, rc.d, งานที่กำหนดเวลาไว้, กระบวนการที่สร้างใหม่ หรือไม่สามารถทำได้ (การอัปเดตยังดำเนินการได้สำเร็จ) ทำงานโดยได้รับอนุญาตจากเจ้าของการติดตั้ง ตัวอัปเดตไม่ได้ยกระดับสิทธิ์ บรรทัดคำสั่งที่บันทึกไว้ระหว่างการรีสตาร์ท redact ค่า `--token` หาก Windows Agent ก่อนหน้านี้ยังคงทำงานจากการสำรองข้อมูล ให้รีสตาร์ทก่อนที่จะอัปเดตอีกครั้ง

## อัปเดตอัตโนมัติ (เดสก์ท็อป Agent daemon)

เมื่อ Agent daemon ทำงาน (ไม่ใช่ `update self` แบบ one-shot) ** จะตรวจสอบ ** รายการเว็บไซต์เดียวกันเป็นระยะ และใช้การอัปเดตเมื่อไบนารี `remote-agent` ที่เผยแพร่แตกต่างออกไป (การเปรียบเทียบแฮช) ค่าเริ่มต้น:

- **Eเปิดใช้งานโดยค่าเริ่มต้น** บนเดสก์ท็อปบิลด์ที่รองรับ (Windows x64/arm64 / Linux x64/arm64 glibc และ musl / macOS arm64 / FreeBSD และ NetBSD x64/arm64)
- ปิดใช้งานด้วยสภาพแวดล้อม `REMOTE_AUTO_UPDATE=0` (เช่น `false` / `no` / `off`), JSON config `"auto_update": false` หรือ CLI `--auto-update false`
- ตรวจสอบครั้งแรก ~90 วินาทีหลังจากสตาร์ท จากนั้นประมาณทุกๆ 12 ชั่วโมง (ไม่ใช่ทุกการเต้นของหัวใจ)
- บันทึกความคืบหน้าอย่างชัดเจน **never** ส่งโทเค็นอุปกรณ์ไปยัง CDN การอัปเดต
- OpenWrt (รวมถึง musl tarball บนโฮสต์ OpenWrt) ข้ามการอัปเดตอัตโนมัติของเดสก์ท็อป Android ใช้เส้นทาง OTA ของตัวเอง สถาปัตยกรรมที่ไม่ได้แมป เช่น Intel Mac หรือ ARM 32 บิตส่งคืนข้อผิดพลาดที่หายไปในการเก็บถาวร และไม่สามารถอัปเดตอัตโนมัติได้

## การอัปเดตแบบพุช Remote (โอเปอเรเตอร์ → อุปกรณ์)

ผู้ดำเนินการที่มีเซสชันอุปกรณ์ทั่วไป (ACL เดียวกันกับ `OpenExec`) สามารถขอให้อุปกรณ์ออนไลน์ตรวจสอบหรือใช้การอัปเดตได้:

โปรโตคอล (WebSocket JSON):

- `OperatorUp::update_device` `{ session_id, device_id, check_only, source? }`
- Exchange → `DeviceDown::update_req`
- อุปกรณ์ → โปรเกรสซีฟ `DeviceUp::update_status` / `OperatorDown::update_status` พร้อม `phase`:
  `checking` | `downloading` | `applying` | `up_to_date` | `available` | `applied` | `error`

Console: ในรายละเอียดอุปกรณ์ **ตรวจสอบการอัปเดต** / **Push update**

CLI (รูปแบบเดียวกับการทำงานของเซสชันอุปกรณ์อื่น):

```sh
remote-cli device update <device_id> --check
remote-cli device update <device_id>
remote-cli device update <device_id> --source https://r2.ivjn.us
```

การควบคุม LAN แมป `update_device` ในลักษณะเดียวกับข้อความ open-* อื่นๆ ของ `OperatorUp` เมื่อเปิดใช้งาน LAN

OpenWrt / Agent อื่นๆ ที่ไม่รองรับจะส่งคืนเฟส `error` ที่ชัดเจน แทนที่จะติดตั้งส่วนผิด Windows arm64, Linux musl, macOS Apple Silicon และ FreeBSD/NetBSD ใช้พาธการเก็บถาวรเดสก์ท็อปเดียวกันกับ Windows x64 และ Linux glibc

## Android Agent OTA

Android Agent APK (`remote-agent-android.apk` บนเว็บไซต์) สามารถอัปเดตตัวเองได้จากรายการ HTTPS เดียวกัน:

เปิด **Settings → ตรวจสอบการอัปเดต ** ใน Agent เพื่อตรวจสอบด้วยตนเอง เช็คจะดาวน์โหลดและตรวจสอบ APK; การอัปเดตที่มีอยู่ต้องมีการยืนยันแยกต่างหากก่อนเปิดตัวติดตั้ง Android

- ดาวน์โหลด APK ตรวจสอบ **bytes + sha256** เปรียบเทียบ `versionCode` / ชื่อแพ็คเกจกับแอปที่ติดตั้ง (เวอร์ชันเดียวกันที่สร้างใหม่ด้วยแฮชอื่นอาจยังติดตั้งอยู่)
- ติดตั้งผ่าน `PackageInstaller` แอปประกาศ `REQUEST_INSTALL_PACKAGES`; ใน OTA แรก ผู้ใช้อาจต้องอนุญาต "ติดตั้งแอปที่ไม่รู้จัก" สำหรับ Remote Agent ในการตั้งค่าระบบ จากนั้นยืนยัน UI ตัวติดตั้งระบบเมื่อแสดง
- การเริ่มการติดตั้งจะส่งคืน `available` พร้อมด้วยข้อความรอการติดตั้ง ไม่ใช่ `applied`
  การโทรกลับของผู้ติดตั้งส่วนตัวจะเปิดหน้าจอยืนยันระบบ คำขอซ้ำแล้วซ้ำอีก
  สำหรับ APK ที่ค้างอยู่เดียวกัน ให้ใช้เซสชันซ้ำ เซสชันการอัปเดตตัวเองที่ล้มเหลวและเก่าคือ
  ถูกทอดทิ้ง ยืนยันเวอร์ชัน/แฮชที่ติดตั้งหลังจากเชื่อมต่อ Agent อีกครั้ง
- การตรวจสอบอัตโนมัติทำงานในช่วงเวลาใกล้เคียงกันในขณะที่ `AgentService` กำลังทำงานอยู่
- Remote `update_req` ได้รับการจัดการโดย Agent ดั้งเดิม ซึ่งเรียกบริดจ์ควบคุม APK (`action: ota_update`)
- ที่เก็บข้อมูลส่วนตัวของแอป (รหัสอุปกรณ์ / โทเค็น) จะถูกเก็บรักษาไว้ตลอดการเปลี่ยนแพ็คเกจ `MY_PACKAGE_REPLACED` ยังคงรีสตาร์ทการเชื่อมต่อเมื่อเปิดใช้งาน

ตอนนี้ส่วนประกอบทั้งหมดแชร์เวอร์ชันวางจำหน่าย 0.1.27: Rust Agent/CLI/Exchange, ส่วนขยายเบราว์เซอร์, แอป Android และเว็บคอนโซล เพิ่มเวอร์ชันด้วยกัน Android versionCode คือ 30 เรียกใช้ `python scripts/check-release-versions.py` ก่อนบรรจุภัณฑ์

## อัปเดต Android Console

Console แบบเนทีฟมีการตั้งค่า **Settings → ตรวจสอบการอัปเดตปุ่ม ** ซึ่งพร้อมใช้งานก่อนหรือหลังการเข้าสู่ระบบ โดยจะอ่านรายการเว็บไซต์สาธารณะโดยไม่มีข้อมูลรับรองบัญชี และเปรียบเทียบบิลด์ที่ติดตั้งกับ `versionCode` ที่เผยแพร่ หากไฟล์ Manifest ไม่มีข้อมูลเมตาของบิลด์และเวอร์ชันทางการตลาดตรงกัน จะเสนอให้ดาวน์โหลดโดยไม่ต้องอ้างว่าแอปที่ติดตั้งนั้นเป็นเวอร์ชันปัจจุบัน

**ตัวติดตั้งดาวน์โหลด** เปิดเว็บไซต์ APK ในเบราว์เซอร์ เสร็จสิ้นการติดตั้งผ่านหน้าจอยืนยันของ Android นี่เป็นการอัปเดต Console บนโทรศัพท์ปัจจุบัน การควบคุมการอัปเดตในหน้ารายละเอียดอุปกรณ์ยังคงกำหนดเป้าหมายไปที่อุปกรณ์ระยะไกลนั้น

## Console "ตรวจสอบการอัปเดต" (เวิร์กโฟลว์แบบรวม)

รายละเอียดอุปกรณ์จะแสดงการดำเนินการ "ตรวจสอบการอัปเดต" เพียงครั้งเดียว ซึ่งจะส่ง `update_device { check_only: true }` ออกมาก่อน:

- `up_to_date`: แสดง "มีเวอร์ชันล่าสุดแล้ว x.y.z"
- `available`: แสดง "ปัจจุบัน → ล่าสุด (ขนาด)" และเสนอ "Push update / later" หลังจากยืนยันแล้ว ให้ส่ง `check_only: false` และแสดงความคืบหน้าและผลลัพธ์
- หาก Android ส่งคืน "Installation pending …" หลังจากการกด ให้ผู้ใช้ยืนยันตัวติดตั้งระบบบนอุปกรณ์
- อุปกรณ์ออฟไลน์และอุปกรณ์เบราว์เซอร์แสดงเหตุผลโดยตรง แพลตฟอร์มที่ไม่รองรับจะแสดงข้อความ "อุปกรณ์นี้ไม่รองรับการอัปเดตระยะไกล"

ข้อความผลลัพธ์ประกอบด้วย `current <版本>` และ `size <字节> bytes`

ดูเพิ่มเติมที่ที่เก็บ `docs/watchdog.md` สำหรับ liveness watchdog เสริม (`--watchdog`, `REMOTE_WATCHDOG=1`)

Android Diagnostics แสดงผลการอัปเดตอัตโนมัติล่าสุดและการประทับเวลาแม้ว่าจะไม่ได้รับอนุญาต READ_LOGS ก็ตาม แก้ไขสาเหตุของความล้มเหลวในการแยกแยะสถานะ HTTP, DNS, หมดเวลา, TLS, รายการ, ขนาด APK/แฮช และความล้มเหลวในการอนุญาตการติดตั้ง ข้อความที่ปลอดภัยเดียวกันนี้เขียนถึง logcat เป็น RemoteAgentOTA; บันทึกอุปกรณ์แบบเต็มยังคงต้องมี READ_LOGS URL เส้นทาง และข้อมูลรับรองที่เป็นข้อยกเว้นจะไม่ถูกคัดลอกไปยังสถานะนี้
