From 97842276c8e42aba4c899842e7ab9e8fa3540f39 Mon Sep 17 00:00:00 2001 From: Petr Polezhaev Date: Tue, 29 Sep 2026 01:30:30 +0300 Subject: [PATCH] =?UTF-8?q?core(M4):=20=D0=BF=D0=BE=D0=BB=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BF=D0=BE=20=D0=BD=D0=B8=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=20=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fglair-discover: fchmod 0600 и при перезаписи существующего --out. - fglctl: #include ; точная проверка обрезки config (n == sizeof-1 && !feof); валидация 'monitor ' (endptr/errno). - docs: отчёт soak — формулировка «ответы на batch GET»; индекс reports. Ревью M4 независимым агентом: 2 круга, APPROVED. --- docs/README.md | 1 + docs/reports/M4_SOAK.md | 2 +- examples/cli/fglctl.cpp | 17 +++++++++++++++-- tools/fglair-discover | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index cfc98a5..ef719a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,7 @@ docs/ # документация (ниже) + матер | `../README.md` | README библиотеки: сборка POSIX/ESP-IDF, тесты, fglctl, `tools/fglair-discover`. | | `../tools/fglair-discover` | Облачный provisioning (ключ устройства, `--format esphome-secrets`). | | `../examples/cli/fglctl.cpp` | Пример CLI на публичном API. | +| `reports/M4_SOAK.md` | Отчёт приёмочного soak-прогона на приборе (60 мин, 0 рассинхронов). | ## Краткая выжимка протокола diff --git a/docs/reports/M4_SOAK.md b/docs/reports/M4_SOAK.md index 28fb9b2..6a3b32e 100644 --- a/docs/reports/M4_SOAK.md +++ b/docs/reports/M4_SOAK.md @@ -12,7 +12,7 @@ |---------|----------| | Смены состояний | registering → online → idle (stop) | | recovering / offline / KEY_ERROR | **0** | -| Push'ей свойств | 33 (все свойства шаблона A, вкл. строковые) | +| Свойств получено | 33 (ответы на стартовый batch GET, все свойства шаблона A, вкл. строковые) | | Push'ей со статусом ≠ 200 | **0** | | `pushes_ok` / `pushes_bad` | 33 / **0** | | Опросов `commands.json` модулем | 273 (~каждые 13 с) | diff --git a/examples/cli/fglctl.cpp b/examples/cli/fglctl.cpp index c9bb56d..8b56ca6 100644 --- a/examples/cli/fglctl.cpp +++ b/examples/cli/fglctl.cpp @@ -10,6 +10,7 @@ // "lanip_key_id": N, "model": "AP-WC1E", ...} #include #include +#include #include #include #include @@ -70,7 +71,7 @@ bool load_config(const char* path, fgl::aircon::Config* cfg, } static char buf[4096]; size_t n = fread(buf, 1, sizeof(buf) - 1, f); - bool truncated = !feof(f); + bool truncated = n == sizeof(buf) - 1 && !feof(f); fclose(f); buf[n] = '\0'; if (truncated) { @@ -181,7 +182,18 @@ int main(int argc, char** argv) { const char* cmd = argv[2]; int rc = 0; if (strcmp(cmd, "monitor") == 0) { - int secs = argc > 3 ? atoi(argv[3]) : 60; + int secs = 60; + if (argc > 3) { + char* end = nullptr; + errno = 0; + long v = strtol(argv[3], &end, 10); + if (errno != 0 || end == argv[3] || *end != '\0' || v < 0) { + fprintf(stderr, "Некорректная длительность: %s\n", argv[3]); + rc = 2; + goto cleanup; + } + secs = static_cast(v); + } if ((rc = wait_online(s, 15000)) == 0) { s->batch_begin(); for (auto* info = fgl::aircon::prop_info_begin(tmpl); @@ -249,6 +261,7 @@ int main(int argc, char** argv) { rc = 2; } +cleanup: print_stats(s); s->stop(); delete s; diff --git a/tools/fglair-discover b/tools/fglair-discover index e15dc37..a021155 100755 --- a/tools/fglair-discover +++ b/tools/fglair-discover @@ -208,6 +208,7 @@ def main(): if args.out: # Ключ устройства — секрет: файл только для владельца. fd = os.open(args.out, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + os.fchmod(fd, 0o600) # и при перезаписи существующего файла with os.fdopen(fd, "w") as f: f.write(text) print(f"Записано: {args.out} (права 0600)", file=sys.stderr)