// Тестовый раннер сессии: поднимает fgl::ayla::Session против mock_ac.py // (или реального модуля) и печатает события строками в stdout: // STATE — смена состояния // PROP — push свойства // DELETED — delete_session забран модулем // STATS ... — телеметрия (перед выходом) // Управление окружением: // RUNNER_KEEPALIVE_MS, RUNNER_ACTIVATION_MS, RUNNER_QUIET_MS, // RUNNER_NOSLOT_RETRY_MS, RUNNER_DELETE_WAIT_MS // RUNNER_SET_NAME/VALUE/AT — одиночная SET через AT секунд после старта. #include #include #include #include #include #include "ayla/session.hpp" using fgl::ayla::PropertyEvent; using fgl::ayla::Session; using fgl::ayla::SessionError; using fgl::ayla::SessionState; static const char* state_name(SessionState st) { switch (st) { case SessionState::kIdle: return "idle"; case SessionState::kRegistering: return "registering"; case SessionState::kOnline: return "online"; case SessionState::kRecovering: return "recovering"; case SessionState::kOffline: return "offline"; case SessionState::kKeyError: return "key_error"; } return "?"; } static uint32_t env_u32(const char* name, uint32_t def) { const char* v = getenv(name); return v != nullptr ? static_cast(atoi(v)) : def; } static void on_state(void*, SessionState st, SessionError err) { printf("STATE %s %d\n", state_name(st), static_cast(err)); fflush(stdout); } static void on_property(void*, const PropertyEvent& ev) { if (ev.is_int) { printf("PROP %s %d %d i:%lld\n", ev.name, ev.cmd_id, ev.status, static_cast(ev.int_value)); } else if (ev.is_bool) { printf("PROP %s %d %d b:%d\n", ev.name, ev.cmd_id, ev.status, ev.bool_value ? 1 : 0); } else { printf("PROP %s %d %d s:%s\n", ev.name, ev.cmd_id, ev.status, ev.str_value); } fflush(stdout); } int main(int argc, char** argv) { if (argc < 7) { fprintf(stderr, "usage: %s " " [prop ...]\n", argv[0]); return 2; } fgl::ayla::SessionConfig cfg{}; cfg.host = argv[1]; cfg.device_port = static_cast(atoi(argv[2])); cfg.listen_port = static_cast(atoi(argv[3])); cfg.dsn = argv[4]; cfg.lanip_key = argv[5]; cfg.lanip_key_id = static_cast(atoi(argv[6])); int duration_sec = atoi(argv[7]); fgl::ayla::SessionCallbacks cbs{}; cbs.on_state = on_state; cbs.on_property = on_property; Session* s = Session::create(cfg, cbs); if (s == nullptr) { fprintf(stderr, "create failed\n"); return 2; } fgl::ayla::SessionTimings timings{}; timings.keepalive_ms = env_u32("RUNNER_KEEPALIVE_MS", timings.keepalive_ms); timings.activation_timeout_ms = env_u32("RUNNER_ACTIVATION_MS", timings.activation_timeout_ms); timings.recovering_quiet_ms = env_u32("RUNNER_QUIET_MS", timings.recovering_quiet_ms); timings.no_slot_retry_ms = env_u32("RUNNER_NOSLOT_RETRY_MS", timings.no_slot_retry_ms); timings.delete_wait_ms = env_u32("RUNNER_DELETE_WAIT_MS", timings.delete_wait_ms); s->set_timings_for_test(timings); if (!s->start()) { fprintf(stderr, "start failed\n"); return 2; } // Начальная синхронизация: пакет GET всех свойств. if (argc > 8) { s->begin_batch(); for (int i = 8; i < argc; i++) { s->get_property(argv[i]); } s->commit_batch(); } const char* set_name = getenv("RUNNER_SET_NAME"); const char* set_val = getenv("RUNNER_SET_VALUE"); uint32_t set_at = env_u32("RUNNER_SET_AT", 0); if (set_name != nullptr && set_val != nullptr && set_at > 0) { std::this_thread::sleep_for(std::chrono::seconds(set_at)); s->set_property(set_name, atoll(set_val)); printf("SET_DONE %s=%s\n", set_name, set_val); fflush(stdout); } auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(duration_sec); while (std::chrono::steady_clock::now() < deadline) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } s->stop(); // внутри: delete_session + ожидание выдачи printf("DELETED\n"); printf("STATS rekeys=%u pushes_ok=%u pushes_bad=%u cmds=%u state=%s\n", s->rekey_count(), s->pushes_ok(), s->pushes_bad(), s->commands_served(), state_name(s->state())); fflush(stdout); delete s; return 0; }