Наблюдател на състоянието на OpenVPN на C#: следете сесията, а не мрежовата карта
NetworkAvailabilityChanged не е VPN събитие. Четете потока на състоянието от клиента собственик, пазете се от остарели проверки и публикувайте готовност за всяка връзка.
Приложението ви продължава да работи, докато тунелът умира. Wi-Fi все още е включен, интернетът още отговаря, а частният API, от който зависи приложението, е станал недостъпен. Събитието в .NET, към което хората обикновено се обръщат тук, NetworkAvailabilityChanged, изобщо не описва тази ситуация. То съобщава за промяна в общото състояние на машината и това състояние може да остане вярно през изключване и повторно свързване на VPN. Наблюдателят трябва да следи клиента, който притежава тунела, а не обобщението на мрежовия стек за него.
Достъпността е обобщена величина, а не вашият тунел
NetworkAvailabilityChanged се задейства, когато общият отговор за достъпност на машината се промени, и този отговор отчита всеки активен интерфейс освен loopback или тунел.
Прекъсване на VPN при включен Wi-Fi не променя нищо, което тя измерва, затова събитието може да мълчи точно през отказа, който ви интересува.
Потокът на състоянието принадлежи на клиента, който притежава тунела
Определете кой компонент притежава връзката: OpenVPN GUI или услугата, OpenVPN Connect или процес, който приложението ви е стартирало и управлява. Това са различни собственици с различни поддържани интерфейси и наблюдателят трябва да използва този, който отговаря на внедряването. За процес на OpenVPN, с който имате разрешение да се интегрирате, интерфейсът за управление съобщава текущото състояние, история и известия в реално време. Анализирайте документираните структурирани съобщения, вместо да търсите в локализиран надпис на GUI думата connected.
Каналът за управление е привилегирована повърхност за контрол, затова не отваряйте нов слушател и не се борете с GUI за канал, който той вече държи.
Защитите по поколение спират остарели резултати
Всяко наблюдение принадлежи на конкретен опит за свързване. Увеличавайте брояч на поколението при започване на нов опит, при загуба на канала и когато клиентът съобщи за изход.
Да разгледаме проверка, започнала по време на връзка A. Тунелът пада, връзка B започва и след това пристига закъснелият HTTP успех на A. Без защита старият резултат прави екрана зелен, докато B още се удостоверява. Отмяната намалява прахосаната работа, а проверката на поколението е това, което не позволява на остаряло завършване да стане текущо състояние:
var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);
Прилагайте същото правило около изпращането към UI, защото маршалираното обновяване може да пристигне, след като поколението е напреднало.
Инициализацията и повторното свързване са един жизнен цикъл
Третирайте първото свързване, повторното свързване и загубата на канала като един жизнен цикъл с един набор от правила:
- Прочетете текущото състояние и се абонирайте за известия в една стъпка, където интерфейсът го позволява.
- Маркирайте всяко наблюдение с идентичността на връзката и поколението.
- Обявявайте готовността за невалидна при повторно свързване, изход или загубен канал за наблюдение.
- Проверявайте частния ресурс само след като собственикът съобщи, че инициализацията е завършена.
- Публикувайте само резултати, които все още принадлежат на текущото поколение.
Загубеният канал означава неизвестно, а не прекъснато. Съобщаването на неизвестно е по-честно от съобщаването на прекъсване, което не можете да докажете, и не позволява на логиката за повторни опити да действа по предположение.
Съобщавайте доказателства, а не булева стойност
Връщайте именуваното състояние на сесията и готовността на ресурса като отделни стойности, всяка с възраст. Тогава потребител, който трябва да реши нещо, може да види, че последната успешна проверка е на четиридесет секунди, което е различна информация от прясната.
Търсенето на публичен IP не е доказателство, че частен API е използвал необходимия маршрут, затова не го представяйте като такова.
Дръжте прилагането извън наблюдателя
Обратното извикване се изпълнява след факта. То не може да гарантира, че между събитието и обработчика от машината не е излязъл нито един пакет. Ако дизайнът изисква блокиране, мрежовата политика трябва да го осигури, а работата на наблюдателя е да обясни доказателствата на извикващия. Смесването на двете създава код, който вярва, че е защитна стена, защото държи булева стойност. Дръжте слоя за прилагане скучен и тестваем, а наблюдателят нека остане читател.
Тогава въпросът за UI става прост: покажете какво е известно, с неговата възраст, и кажете неизвестно, когато е така.