mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
perf(portals): fast-fail requests to portal hosts that stopped answering (#1421)
This commit is contained in:
1 parent
2d7811eb5f
commit
e3f72f7dce
50 files changed
+3073
-174
No files matched your search
@@ -14,6 +14,7 @@ export * from './lib/epg-program.model';
|
||||
export * from './lib/external-player-arguments.utils';
|
||||
export * from './lib/external-player-session.interface';
|
||||
export * from './lib/global-search-result.interface';
|
||||
export * from './lib/host-connectivity.util';
|
||||
export * from './lib/indexed-db.config';
|
||||
export * from './lib/ipc-command.class';
|
||||
export * from './lib/ipc-commands';
|
||||
|
||||
@@ -283,6 +283,13 @@ export interface ElectronBridgeStalkerRequestPayload {
|
||||
token?: string;
|
||||
serialNumber?: string;
|
||||
requestId?: string;
|
||||
/**
|
||||
* Endpoint-discovery probes only: exempt this request from the main
|
||||
* process' per-host connectivity guard. Discovery walks several candidate
|
||||
* paths on one host and expects most of them to fail, so its failures must
|
||||
* neither count towards the guard nor be fast-failed by it.
|
||||
*/
|
||||
skipConnectionGuard?: boolean;
|
||||
}
|
||||
|
||||
export interface ElectronBridgeXtreamRequestPayload {
|
||||
@@ -774,6 +781,11 @@ export interface ElectronBridgeApi {
|
||||
stalkerRequest: (
|
||||
payload: ElectronBridgeStalkerRequestPayload
|
||||
) => Promise<Record<string, unknown>>;
|
||||
/**
|
||||
* Forgets the connection failures recorded for the host `url` points at, so
|
||||
* the next request contacts it for real instead of being fast-failed.
|
||||
*/
|
||||
resetHostConnectivityGuard: (url: string) => Promise<ElectronBridgeResult>;
|
||||
xtreamRequest: (
|
||||
payload: ElectronBridgeXtreamRequestPayload
|
||||
) => Promise<ElectronBridgeXtreamResponse>;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Cross-process contract for the main-process host connectivity guard.
|
||||
*
|
||||
* The guard fast-fails requests to a portal host that just failed to answer
|
||||
* several times in a row, instead of hanging the full axios timeout again.
|
||||
*
|
||||
* Only the MESSAGE of a rejected IPC handler survives the trip to the
|
||||
* renderer — `ipcRenderer.invoke` strips custom properties and re-wraps the
|
||||
* value — and the Stalker renderer classifies transport failures purely from
|
||||
* that text. The wording below is therefore a contract, not a label:
|
||||
*
|
||||
* - no `HTTP Error <code>`: `getStalkerRequestErrorStatus` would report a
|
||||
* status, so endpoint discovery would read "this endpoint is absent, probe
|
||||
* the next candidate", and 404/401/403 would additionally fire lazy portal
|
||||
* repair against a host we just declared dead;
|
||||
* - no timeout wording: `isStalkerProbeTimeout` would keep discovery walking
|
||||
* every candidate instead of aborting on the first one;
|
||||
* - none of the auth phrases `isStalkerAuthFailureMessage` accepts (a bare
|
||||
* `authorization` is one of them) — that would also trigger lazy repair.
|
||||
*
|
||||
* What is left is the "connection-level failure" slot the renderer already
|
||||
* has for ECONNREFUSED/ENOTFOUND: discovery stops probing and reports the
|
||||
* host unreachable, which is exactly what a tripped guard means. The message
|
||||
* also reaches error snackbars verbatim, so it has to read like a sentence.
|
||||
*
|
||||
* `endpoint` is the request origin (scheme, host and port), not a bare host: a
|
||||
* user with the same panel imported over both HTTP and HTTPS needs to see which
|
||||
* of the two was skipped. A scheme is safe here — none of the forbidden
|
||||
* substrings above can appear in one.
|
||||
*/
|
||||
export function buildHostConnectivityFastFailMessage(endpoint: string): string {
|
||||
return `Portal ${endpoint} is not responding; skipped after repeated connection failures`;
|
||||
}
|
||||
|
||||
const FAST_FAIL_MESSAGE_PATTERN =
|
||||
/is not responding; skipped after repeated connection failures/;
|
||||
|
||||
/**
|
||||
* Whether a message came from the guard, bare or in the form Electron wraps
|
||||
* it into (`Error invoking remote method 'STALKER_REQUEST': <message>`).
|
||||
*
|
||||
* Exported so tests and any future renderer-side handling share one
|
||||
* definition of the wording instead of re-typing the sentence.
|
||||
*/
|
||||
export function isHostConnectivityFastFailMessage(message: unknown): boolean {
|
||||
return (
|
||||
typeof message === 'string' && FAST_FAIL_MESSAGE_PATTERN.test(message)
|
||||
);
|
||||
}
|
||||
@@ -100,6 +100,14 @@ export const STALKER_REQUEST = 'STALKER_REQUEST';
|
||||
export const STALKER_RESPONSE = 'STALKER_RESPONSE';
|
||||
export const PORTAL_DEBUG_EVENT = 'PORTAL_DEBUG_EVENT';
|
||||
|
||||
/**
|
||||
* Forgets the main process' recorded connection failures for a portal host, so
|
||||
* the next request contacts it for real. Sent whenever the user asks for a
|
||||
* fresh attempt (portal retry, "test connection") or hands over a possibly
|
||||
* different portal (endpoint discovery on import, edit, or lazy repair).
|
||||
*/
|
||||
export const CONNECTIVITY_GUARD_RESET = 'CONNECTIVITY_GUARD_RESET';
|
||||
|
||||
// Settings
|
||||
export const SETTINGS_UPDATE = 'SETTINGS_UPDATE';
|
||||
export const DELETE_ALL_PLAYLISTS = 'DELETE_ALL_PLAYLISTS';
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
* URL builders were centralised here. Two copies would drift.
|
||||
*/
|
||||
|
||||
import { isHostConnectivityFastFailMessage } from './host-connectivity.util';
|
||||
|
||||
/** The exact plain-text bodies the stock middleware emits. */
|
||||
export const STALKER_AUTH_FAILURE_BODIES = [
|
||||
'Authorization failed.',
|
||||
@@ -122,9 +124,19 @@ function isStalkerJsonAuthFailurePhrase(value: string): boolean {
|
||||
* arbitrary portal body, where the same breadth would false-positive.
|
||||
*/
|
||||
export function isStalkerAuthFailureMessage(message: unknown): boolean {
|
||||
return (
|
||||
typeof message === 'string' && isStalkerJsonAuthFailurePhrase(message)
|
||||
);
|
||||
if (typeof message !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The connectivity guard's refusal names the portal endpoint, and a
|
||||
// hostname is user data: `https://authorization.example` would otherwise
|
||||
// match the broad phrase set below and send an unreachable host into lazy
|
||||
// portal repair. An explicit marker outranks a heuristic.
|
||||
if (isHostConnectivityFastFailMessage(message)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isStalkerJsonAuthFailurePhrase(message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user