feat(session): add explicit leave and immediate slot release

This commit is contained in:
2026-09-13 22:53:18 +03:00
parent 44433aee9c
commit b6d484dbc9
16 changed files with 526 additions and 13 deletions
+48 -3
View File
@@ -948,6 +948,40 @@ static void handle_message(maze32_gateway_t* gateway, maze32_gateway_connection_
"Сначала выберите роль или восстановите сессию");
return;
}
if (message->type == MAZE32_MESSAGE_LEAVE) {
maze32_role_t leaving_role = session->role;
int cancel_match = leaving_role == MAZE32_ROLE_PLAYER &&
gateway->lobby.phase != MAZE32_LOBBY_WAITING &&
gateway->game.phase != MAZE32_GAME_PHASE_FINISHED;
char acknowledgement[192] = "";
size_t length = 0U;
char prefix[96];
int written = snprintf(prefix, sizeof(prefix),
"{\"v\":1,\"type\":\"ack\",\"seq\":%" PRIu32 ",\"requestId\":",
next_server_sequence(gateway));
if (written >= 0 && (size_t)written < sizeof(prefix) &&
append_text(acknowledgement, sizeof(acknowledgement), &length, prefix) &&
append_json_string(acknowledgement, sizeof(acknowledgement), &length,
message->request_id) &&
append_text(acknowledgement, sizeof(acknowledgement), &length,
",\"payload\":{\"command\":\"leave\"}}")) {
enqueue(gateway, socket_fd, acknowledgement);
}
if (cancel_match) {
esp_timer_stop(gateway->countdown_timer);
esp_timer_stop(gateway->reconnect_timer);
esp_timer_stop(gateway->finish_timer);
initialize_game(gateway);
maze32_lobby_reset_match(&gateway->lobby);
}
maze32_lobby_leave(&gateway->lobby, socket_fd, NULL, NULL);
if (cancel_match) {
broadcast_match_event(gateway, "reset", "{}");
}
broadcast_snapshot(gateway);
drain_queue(gateway);
return;
}
if (message->type == MAZE32_MESSAGE_START) {
if (session->role == MAZE32_ROLE_OBSERVER) {
ESP_LOGW(TAG, "Observer mutation rejected: fd=%d, type=start", socket_fd);
@@ -977,18 +1011,29 @@ static void handle_message(maze32_gateway_t* gateway, maze32_gateway_connection_
return;
}
if (message->type == MAZE32_MESSAGE_HEARTBEAT) {
int64_t heartbeat_started_us = esp_timer_get_time();
char response[MAZE32_GATEWAY_OUTGOING_LIMIT] = "";
size_t length = 0U;
char prefix[128];
char handling_text[32];
int written = snprintf(prefix, sizeof(prefix), "{\"v\":1,\"type\":\"ack\",\"seq\":%" PRIu32,
next_server_sequence(gateway));
if (written >= 0 && (size_t)written < sizeof(prefix) &&
uint64_t handling_ms = (uint64_t)(esp_timer_get_time() - heartbeat_started_us) / 1000U;
if (handling_ms > 1000U) {
handling_ms = 1000U;
}
int handling_written =
snprintf(handling_text, sizeof(handling_text), "%" PRIu64, handling_ms);
if (written >= 0 && (size_t)written < sizeof(prefix) && handling_written >= 0 &&
(size_t)handling_written < sizeof(handling_text) &&
append_text(response, sizeof(response), &length, prefix) &&
append_text(response, sizeof(response), &length, ",\"requestId\":") &&
append_json_string(response, sizeof(response), &length, message->request_id) &&
append_text(response, sizeof(response), &length,
",\"payload\":{\"command\":\"heartbeat\"}}")) {
enqueue(gateway, socket_fd, response);
",\"payload\":{\"command\":\"heartbeat\",\"handlingMs\":") &&
append_text(response, sizeof(response), &length, handling_text) &&
append_text(response, sizeof(response), &length, "}}")) {
enqueue_with_policy(gateway, socket_fd, response, 1);
}
}
}