diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb29d77..afd01ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,8 +15,10 @@ env: # from frontend/package-lock.json GAMEAP_REF: main # Ref of gameap/gameap-proto providing rust/gameap-plugin-sdk; pin to a SHA if - # the SDK drifts from Cargo.lock - GAMEAP_PROTO_REF: main + # the SDK drifts from Cargo.lock. Pinned to the head of the proto-updates + # branch: HTTPResponse.file / FileRef, which src/http.rs sets, is not on main + # yet. Restore `main` once proto-updates is merged. + GAMEAP_PROTO_REF: aba9a6c002358ed56691ff1f5c28d448e5f2cdee jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7351e46..7f5180c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,8 +12,10 @@ env: # from frontend/package-lock.json GAMEAP_REF: main # Ref of gameap/gameap-proto providing rust/gameap-plugin-sdk; pin to a SHA if - # the SDK drifts from Cargo.lock - GAMEAP_PROTO_REF: main + # the SDK drifts from Cargo.lock. Pinned to the head of the proto-updates + # branch: HTTPResponse.file / FileRef, which src/http.rs sets, is not on main + # yet. Restore `main` once proto-updates is merged. + GAMEAP_PROTO_REF: aba9a6c002358ed56691ff1f5c28d448e5f2cdee jobs: publish: diff --git a/Cargo.lock b/Cargo.lock index 9ccd031..765568d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,7 +45,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "files" -version = "0.7.0" +version = "0.8.0" dependencies = [ "gameap-plugin-sdk", "serde", diff --git a/Cargo.toml b/Cargo.toml index 71ce6c8..e53be89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "files" -version = "0.7.0" +version = "0.8.0" edition = "2024" license = "MIT" publish = false diff --git a/README.md b/README.md index ad85e79..76b80a5 100644 --- a/README.md +++ b/README.md @@ -6,23 +6,31 @@ FTP/SFTP daemon on nodes and manages per-server FTP users, access rules, virtual path mounts and SSH keys. Rust rewrite of the original Go plugin (`plugin-gameap-files`). Storage data, -node-side YAML files and the HTTP API are fully compatible — existing installs -keep working after the swap. +node-side YAML files and the HTTP API are fully compatible, so the panel side +keeps working after the swap. That compatibility does not replace the one-time +node migration every 0.7.x install still needs — see +[Upgrading from 0.7.x](#upgrading-from-07x). *Читайте на других языках: [Русский](README_RU.md)* ## Features -- One-click gameap-files installation on nodes (chained daemon tasks, live - status tracking through daemon-task events with a poll/timeout fallback) +- One-click gameap-files installation on Linux and Windows nodes (chained + daemon tasks, live status tracking through daemon-task events with a + poll/timeout fallback) and an **Update** button that re-runs the installer + with the stored settings to upgrade an installed node - Per-node FTP/SFTP configuration (`config.yaml` is patched in place — keys - the plugin does not own are preserved) + the plugin does not own are preserved); the service is restarted through + the system unit, the user unit of a rootless daemon, or the Windows service - FTP/SFTP users per game server: create/update/delete, Argon2id password hashing via the panel's crypto host service, one-time generated passwords - Path access rules (`read` / `write` / `delete` / `list`), virtual path mounts, SSH public keys - Users are mirrored to nodes as hot-reloaded YAML drop-ins under - `/etc/gameap-files/users.d/` + `/.plugins/files/users.d/` — the plugin's service directory + inside the daemon work path, the one place the daemon lets a panel plugin + write to; a relative `home_dir` is resolved against the node work path + itself, not against that directory - Admin pages: all nodes with install status, all users grouped by node → server with filters - Server abilities `ftp-users-view` / `ftp-users-manage` for non-admin access @@ -59,7 +67,35 @@ Panel KV storage (compatible with the Go plugin): - `SERVER_DELETED` — removes the server's users from storage and their YAML files from the node (node id taken from the event payload) - `DAEMON_TASK_COMPLETED` / `DAEMON_TASK_FAILED` — matched against the - install/download task ids stored in the node's setup status + install/download task ids stored in the node's setup status; a completed + installation re-syncs every user of the node once (`synced_after_install` + in the stored status) and removes the misplaced + `/etc/gameap-files/users.d/*.yaml` files older releases wrote + +### Node layout + +gameap-daemon confines a panel plugin's file operations to the node work +path, so everything this plugin writes is addressed relative to it: + +| Node path (relative to `work_path`) | Contents | +|---|---| +| `.plugins/files/config.yaml` | gameap-files configuration, patched by the settings dialog | +| `.plugins/files/users.d/.yaml` | one drop-in per FTP user | +| `tools/install-files-linux.sh`, `tools/install-files-windows.ps1` | installers fetched with `get-tool` | +| `tools/gameap-files/` (Windows) | binary and service of the Windows install | + +### Upgrading from 0.7.x + +After replacing the plugin, click **Update** once on every node installed by +an earlier release: storage and API compatibility covers the panel side only, +the node side still has to be migrated. The installer moves +`/etc/gameap-files` into `/.plugins/files`, the plugin re-syncs the +node's users from the legacy location and sweeps the files the old release had +left under `/etc/gameap-files`. + +Until **Update** is clicked, such a node keeps reading `/etc/gameap-files`, +**Settings** on it fails with "failed to download config", and users created +in the panel are not seen by gameap-files. ## Building diff --git a/README_RU.md b/README_RU.md index 23d5bf1..17ef912 100644 --- a/README_RU.md +++ b/README_RU.md @@ -7,23 +7,32 @@ FTP-пользователями игровых серверов, правила SSH-ключами. Переписан на Rust с исходного Go-плагина (`plugin-gameap-files`). Данные в -storage, YAML-файлы на нодах и HTTP API полностью совместимы — существующие -установки продолжают работать после замены. +storage, YAML-файлы на нодах и HTTP API полностью совместимы, поэтому сторона +панели продолжает работать после замены. Эта совместимость не отменяет +разовую миграцию, которая нужна каждой ноде с 0.7.x — см. +[Обновление с 0.7.x](#обновление-с-07x). *Read this in other languages: [English](README.md)* ## Возможности -- Установка gameap-files на ноду в один клик (цепочка daemon-тасков, - отслеживание статуса через события с fallback-поллингом и таймаутом) +- Установка gameap-files на Linux- и Windows-ноды в один клик (цепочка + daemon-тасков, отслеживание статуса через события с fallback-поллингом и + таймаутом) и кнопка **Обновить**, которая повторно запускает установщик с + сохранёнными настройками для обновления установленной ноды - Настройка FTP/SFTP per-node (`config.yaml` патчится на месте — чужие ключи - сохраняются) + сохраняются); сервис перезапускается через системный юнит, user-юнит + rootless-демона или службу Windows - FTP/SFTP-пользователи по серверам: создание/изменение/удаление, Argon2id-хэши через crypto-сервис панели, одноразовый показ сгенерированного пароля - Правила доступа по путям (`read` / `write` / `delete` / `list`), виртуальные пути, SSH-ключи - Синхронизация пользователей на ноды YAML-файлами в - `/etc/gameap-files/users.d/` (демон перечитывает их на лету) + `/.plugins/files/users.d/` — сервисный каталог плагина внутри + рабочего каталога демона, единственное место, куда gameap-daemon разрешает + писать плагину панели; относительный `home_dir` раскрывается относительно + рабочего каталога ноды (`work_path`), а не этого каталога; демон + перечитывает файлы на лету - Админ-страницы: список нод со статусами установки, все пользователи с группировкой нода → сервер и фильтрами - Права сервера `ftp-users-view` / `ftp-users-manage` для не-админов @@ -59,7 +68,35 @@ KV-хранилище панели (совместимо с Go-версией): - `SERVER_DELETED` — удаляет пользователей сервера из storage и их YAML с ноды (id ноды берётся из payload события) - `DAEMON_TASK_COMPLETED` / `DAEMON_TASK_FAILED` — сопоставляются с id - install/download-тасков из сохранённого статуса установки + install/download-тасков из сохранённого статуса установки; завершённая + установка один раз пересинхронизирует всех пользователей ноды + (`synced_after_install` в сохранённом статусе) и удаляет ошибочные файлы + `/etc/gameap-files/users.d/*.yaml`, которые писали старые релизы + +### Раскладка на ноде + +gameap-daemon ограничивает файловые операции плагина панели рабочим +каталогом ноды, поэтому все пути плагина относительны к нему: + +| Путь на ноде (относительно `work_path`) | Содержимое | +|---|---| +| `.plugins/files/config.yaml` | конфигурация gameap-files, патчится из диалога настроек | +| `.plugins/files/users.d/.yaml` | по одному файлу на FTP-пользователя | +| `tools/install-files-linux.sh`, `tools/install-files-windows.ps1` | установщики, скачанные через `get-tool` | +| `tools/gameap-files/` (Windows) | бинарник и служба Windows-установки | + +### Обновление с 0.7.x + +После замены плагина нажмите **Обновить** один раз на каждой ноде, +установленной прежним релизом: совместимость storage и API покрывает только +сторону панели, ноду всё равно нужно мигрировать. Установщик переносит +`/etc/gameap-files` в `/.plugins/files`, плагин пересинхронизирует +пользователей ноды из старого расположения и удаляет файлы, которые старый +релиз оставил в `/etc/gameap-files`. + +Пока **Обновить** не нажато, такая нода продолжает читать `/etc/gameap-files`, +**Настройки** на ней падают с ошибкой "failed to download config", а +созданные в панели пользователи не видны gameap-files. ## Сборка diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a8a6815..369ac2b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "plugin-files-frontend", - "version": "0.6.0", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plugin-files-frontend", - "version": "0.6.0", + "version": "0.8.0", "dependencies": { "@gameap/plugin-sdk": "file:../../gameap-api/web/plugin-sdk" }, diff --git a/frontend/package.json b/frontend/package.json index 7a1771d..f92adea 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "plugin-files-frontend", - "version": "0.7.0", + "version": "0.8.0", "description": "GameAP Files Plugin Frontend - FTP/SFTP Users Management", "type": "module", "main": "./dist/plugin.js", diff --git a/frontend/src/components/admin/FtpNodeCard.vue b/frontend/src/components/admin/FtpNodeCard.vue index bad75fd..671c500 100644 --- a/frontend/src/components/admin/FtpNodeCard.vue +++ b/frontend/src/components/admin/FtpNodeCard.vue @@ -61,6 +61,16 @@ {{ trans('view_users') }} + + + {{ trans('update_installation') }} + {{ trans('settings') }} @@ -91,6 +101,8 @@ const props = defineProps<{ const emit = defineEmits<{ setup: [nodeId: number]; + /** Re-run the installer with the stored configuration (upgrade). */ + update: [nodeId: number]; configure: [nodeId: number]; }>(); diff --git a/frontend/src/components/node/NodeStatusCard.vue b/frontend/src/components/node/NodeStatusCard.vue index 9d99dfc..5a1e3a1 100644 --- a/frontend/src/components/node/NodeStatusCard.vue +++ b/frontend/src/components/node/NodeStatusCard.vue @@ -30,9 +30,19 @@ - +