ZaStoGram/TMessagesProj/jni/mtproxy/MtProxyTerminalDiagnostic.cpp
loop-uh 3f8f8f27e7 Extract mtproxy module with unified retry authority
Move MTProxy policy engine from tgnet/ to self-contained jni/mtproxy/ module. Consolidate reconnect hold computation into single MtProxyRetryAuthority owner (was split across Connection, ConnectionSocket, endpoint policy, and probe coordinator, causing hold misalignment bugs). Add MtProxyTerminalDiagnostic module with host tests for pre-I/O verdict preservation (fixes 02.07/30.06 clobber livelocks). Auto-generate phase classification (isPreIoTerminalVerdict, needsReconnectBackoff, isObservationFacadePhase, isLocalSchedulerTimeout) from single Python contract into both C++ and Java to eliminate parallel maintenance. Pass native hold (coordinator terminal hold + endpoint cooldown) via JNI to Java so reconnect timer and health store use THE clock, not re-derived ones. Optimize log flushing: batch debug lines, flush errors immediately. Add module boundary guard, host build system (MSVC), and unit tests for retry logic and terminal diagnostic derivation.
2026-07-02 18:25:13 +03:00

55 lines
2.3 KiB
C++

/*
* This is the source code of tgnet library v. 1.1
* It is licensed under GNU GPL v. 2 or later.
*/
#include "MtProxyTerminalDiagnostic.h"
#include <errno.h>
#include "MtProxyPhaseContract.h"
namespace MtProxyPhase {
TerminalDiagnosticResult deriveTerminalDiagnostic(const TerminalDiagnosticInput &input) {
TerminalDiagnosticResult result;
const std::string current = input.currentDiagnostic != nullptr ? input.currentDiagnostic : "";
// Diagnostics decided pre-I/O (before the socket connects) must survive the close path.
// Re-deriving them from the startup timeline would replace them with
// "connection_not_started" (startupActive is true because the socket never connected),
// which is on the local-scheduler-timeout skip list -> records neither an endpoint
// cooldown nor a reconnect hold -> reconnect hot loop. The phase set is owned by the
// shared contract: MtProxyPhase::isPreIoTerminalVerdict (generated).
if (isPreIoTerminalVerdict(current.c_str())) {
result.diagnostic = current;
return result;
}
if (input.timeline == nullptr) {
result.diagnostic = current.empty() ? std::string("unknown_fail") : current;
return result;
}
bool startupActive = input.timeline->hasLocalWait()
|| input.timeline->dnsResolveAttemptStarted()
|| input.timeline->tcpConnectAttemptStarted()
|| !input.socketConnectedLogged;
if (startupActive) {
const char *timelineDiagnostic = input.timeline->terminalDiagnostic(input.socketConnectedLogged);
if (!input.socketConnectedLogged && input.timeline->tcpConnectAttemptStarted()) {
if (input.socketError == ECONNREFUSED) {
result.diagnostic = MtProxyPhase::TcpConnectionRefused;
return result;
}
if (input.socketError == ETIMEDOUT || input.closeReason == 2 || current == MtProxyPhase::TcpConnectTimeout) {
result.diagnostic = MtProxyPhase::TcpConnectTimeout;
return result;
}
}
result.diagnostic = timelineDiagnostic != nullptr ? timelineDiagnostic : "";
result.timelineDerived = true;
return result;
}
result.diagnostic = current.empty() ? std::string("unknown_fail") : current;
return result;
}
}