core(M4): полировка по нитам финального ревью
- fglair-discover: fchmod 0600 и при перезаписи существующего --out. - fglctl: #include <cstdlib>; точная проверка обрезки config (n == sizeof-1 && !feof); валидация 'monitor <sec>' (endptr/errno). - docs: отчёт soak — формулировка «ответы на batch GET»; индекс reports. Ревью M4 независимым агентом: 2 круга, APPROVED.
This commit is contained in:
@@ -35,6 +35,7 @@ docs/ # документация (ниже) + матер
|
|||||||
| `../README.md` | README библиотеки: сборка POSIX/ESP-IDF, тесты, fglctl, `tools/fglair-discover`. |
|
| `../README.md` | README библиотеки: сборка POSIX/ESP-IDF, тесты, fglctl, `tools/fglair-discover`. |
|
||||||
| `../tools/fglair-discover` | Облачный provisioning (ключ устройства, `--format esphome-secrets`). |
|
| `../tools/fglair-discover` | Облачный provisioning (ключ устройства, `--format esphome-secrets`). |
|
||||||
| `../examples/cli/fglctl.cpp` | Пример CLI на публичном API. |
|
| `../examples/cli/fglctl.cpp` | Пример CLI на публичном API. |
|
||||||
|
| `reports/M4_SOAK.md` | Отчёт приёмочного soak-прогона на приборе (60 мин, 0 рассинхронов). |
|
||||||
|
|
||||||
## Краткая выжимка протокола
|
## Краткая выжимка протокола
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|---------|----------|
|
|---------|----------|
|
||||||
| Смены состояний | registering → online → idle (stop) |
|
| Смены состояний | registering → online → idle (stop) |
|
||||||
| recovering / offline / KEY_ERROR | **0** |
|
| recovering / offline / KEY_ERROR | **0** |
|
||||||
| Push'ей свойств | 33 (все свойства шаблона A, вкл. строковые) |
|
| Свойств получено | 33 (ответы на стартовый batch GET, все свойства шаблона A, вкл. строковые) |
|
||||||
| Push'ей со статусом ≠ 200 | **0** |
|
| Push'ей со статусом ≠ 200 | **0** |
|
||||||
| `pushes_ok` / `pushes_bad` | 33 / **0** |
|
| `pushes_ok` / `pushes_bad` | 33 / **0** |
|
||||||
| Опросов `commands.json` модулем | 273 (~каждые 13 с) |
|
| Опросов `commands.json` модулем | 273 (~каждые 13 с) |
|
||||||
|
|||||||
+15
-2
@@ -10,6 +10,7 @@
|
|||||||
// "lanip_key_id": N, "model": "AP-WC1E", ...}
|
// "lanip_key_id": N, "model": "AP-WC1E", ...}
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -70,7 +71,7 @@ bool load_config(const char* path, fgl::aircon::Config* cfg,
|
|||||||
}
|
}
|
||||||
static char buf[4096];
|
static char buf[4096];
|
||||||
size_t n = fread(buf, 1, sizeof(buf) - 1, f);
|
size_t n = fread(buf, 1, sizeof(buf) - 1, f);
|
||||||
bool truncated = !feof(f);
|
bool truncated = n == sizeof(buf) - 1 && !feof(f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
if (truncated) {
|
if (truncated) {
|
||||||
@@ -181,7 +182,18 @@ int main(int argc, char** argv) {
|
|||||||
const char* cmd = argv[2];
|
const char* cmd = argv[2];
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
if (strcmp(cmd, "monitor") == 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<int>(v);
|
||||||
|
}
|
||||||
if ((rc = wait_online(s, 15000)) == 0) {
|
if ((rc = wait_online(s, 15000)) == 0) {
|
||||||
s->batch_begin();
|
s->batch_begin();
|
||||||
for (auto* info = fgl::aircon::prop_info_begin(tmpl);
|
for (auto* info = fgl::aircon::prop_info_begin(tmpl);
|
||||||
@@ -249,6 +261,7 @@ int main(int argc, char** argv) {
|
|||||||
rc = 2;
|
rc = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
print_stats(s);
|
print_stats(s);
|
||||||
s->stop();
|
s->stop();
|
||||||
delete s;
|
delete s;
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ def main():
|
|||||||
if args.out:
|
if args.out:
|
||||||
# Ключ устройства — секрет: файл только для владельца.
|
# Ключ устройства — секрет: файл только для владельца.
|
||||||
fd = os.open(args.out, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
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:
|
with os.fdopen(fd, "w") as f:
|
||||||
f.write(text)
|
f.write(text)
|
||||||
print(f"Записано: {args.out} (права 0600)", file=sys.stderr)
|
print(f"Записано: {args.out} (права 0600)", file=sys.stderr)
|
||||||
|
|||||||
Reference in New Issue
Block a user