Je applicatie blijft werken terwijl de tunnel sterft. Wi-Fi is nog actief, het internet antwoordt nog, en de private API waarvan de app afhangt, is onbereikbaar geworden. De .NET-gebeurtenis waar mensen hier meestal naar grijpen, NetworkAvailabilityChanged, beschrijft die situatie helemaal niet. Hij meldt een wijziging in de samengestelde toestand van de machine, en die toestand kan waar blijven tijdens een VPN-verbreking en -herverbinding. Een observator moet de client volgen die de tunnel bezit, niet de samenvatting van de netwerkstack.

Beschikbaarheid is een samengestelde waarde, niet je tunnel

NetworkAvailabilityChanged wordt geactiveerd wanneer het samengestelde beschikbaarheidsantwoord van de machine verandert, en dat antwoord telt elke actieve interface behalve loopback of een tunnel.

Een VPN-onderbreking terwijl Wi-Fi actief is, verandert niets van wat hij meet, daarom kan de gebeurtenis stil blijven tijdens precies de storing die je aangaat.

De statusstroom hoort bij de client die de tunnel bezit

Bepaal welk onderdeel de verbinding bezit: de OpenVPN-GUI of -dienst, OpenVPN Connect, of een proces dat je applicatie start en beheert. Dat zijn verschillende eigenaren met verschillende ondersteunde interfaces, en de observator moet degene gebruiken die bij de uitrol past. Voor een OpenVPN-proces waarmee je mag integreren, rapporteert de beheerinterface de huidige toestand, een geschiedenis en realtime meldingen. Analyseer de gedocumenteerde gestructureerde berichten in plaats van in een gelokaliseerd GUI-opschrift naar het woord connected te zoeken.

Het beheerkanaal is een bevoorrecht bedieningsoppervlak, dus open geen nieuwe listener en vecht niet met de GUI om een kanaal dat zij al bezit.

Generatiewachten stoppen verouderde resultaten

Elke observatie hoort bij een specifieke verbindingspoging. Verhoog een generatieteller wanneer een nieuwe poging begint, wanneer het kanaal verloren gaat en wanneer de client een exit meldt.

Denk aan een probe die tijdens verbinding A begon. De tunnel valt weg, verbinding B begint, en daarna komt A's vertraagde HTTP-succes binnen. Zonder wacht maakt dat oude resultaat het scherm groen terwijl B nog authenticeert. Annulering vermindert verspild werk, en de generatiecontrole is wat voorkomt dat een verouderde voltooiing de huidige toestand wordt:

var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);

Pas dezelfde regel toe rond de UI-verzending, want de gemarshallde update kan aankomen nadat de generatie verder is gegaan.

Initialisatie en herverbinding zijn één levenscyclus

Behandel eerste verbinding, herverbinding en kanaalverlies als één levenscyclus met één regelset:

  • Lees de huidige toestand en abonneer je op meldingen in één stap waar de interface dat toestaat.
  • Markeer elke observatie met de identiteit van de verbinding en de generatie.
  • Maak gereedheid ongeldig bij herverbinding, exit of een verloren observatiekanaal.
  • Probeer de private resource pas nadat de eigenaar meldt dat de initialisatie is voltooid.
  • Publiceer alleen resultaten die nog bij de huidige generatie horen.

Een verloren kanaal betekent onbekend, niet verbroken. Onbekend melden is eerlijker dan een verbreking melden die je niet kunt bewijzen, en het voorkomt dat de herhaal-logica op een gok handelt.

Meld bewijs, geen boolean

Retourneer de benoemde sessietoestand en de resourcegereedheid als afzonderlijke waarden, elk met een leeftijd. Een consument die iets moet beslissen, kan dan zien dat de laatste geslaagde probe veertig seconden oud is, wat andere informatie is dan een verse.

Een publieke IP-opzoeking is geen bewijs dat een private API de vereiste route gebruikte, dus presenteer het niet alsof dat zo is.

Houd handhaving buiten de observator

Een callback draait achteraf. Hij kan niet garanderen dat er tussen de gebeurtenis en de handler geen pakket de machine heeft verlaten. Als het ontwerp blokkering vereist, moet het netwerkbeleid die leveren, en de taak van de observator is het bewijs aan de aanroeper uit te leggen. Beide vermengen levert code op die zich een firewall waant omdat hij een boolean bevat. Houd de handhavingslaag saai en testbaar, en laat de observator een lezer blijven.

Dan wordt de UI-vraag eenvoudig: toon wat bekend is, met de leeftijd ervan, en zeg onbekend wanneer dat zo is.

Gerelateerde artikelen