Ваша апликација наставља да ради док тунел умире. Wi-Fi је још активан, интернет још одговара, а приватни API од кога апликација зависи постао је недоступан. .NET догађај коме људи овде обично посежу, NetworkAvailabilityChanged, уопште не описује ту ситуацију. Он пријављује промену у збирном стању машине, а то стање може остати тачно и кроз прекид и поновно успостављање VPN везе. Посматрач мора да гледа клијента који поседује тунел, а не сажетак мрежног стека о њему.

Доступност је збирна вредност, не ваш тунел

NetworkAvailabilityChanged се активира када се збирни одговор машине о доступности промени, а тај одговор рачуна сваки активни интерфејс осим loopback-а или тунела.

Пад VPN-а док је Wi-Fi активан не мења ништа што она мери, зато догађај може остати тих током управо оног квара који вас занима.

Ток стања припада клијенту који поседује тунел

Утврдите која компонента поседује везу: OpenVPN GUI или сервис, OpenVPN Connect, или процес који је ваша апликација покренула и контролише. То су различити власници са различитим подржаним интерфејсима, а посматрач мора да користи онај који одговара постављању. За OpenVPN процес са којим имате овлашћење да се интегришете, управљачки интерфејс пријављује тренутно стање, историју и обавештења у реалном времену. Анализирајте документоване структуриране поруке уместо да у локализованом GUI натпису тражите реч connected.

Управљачки канал је привилегована контролна површина, зато не отварајте нови слушалац и не свађајте се са GUI-јем око канала који он већ држи.

Генерацијске заштите заустављају застареле резултате

Свако посматрање припада одређеном покушају повезивања. Повећајте бројач генерације када почне нови покушај, када се изгуби канал и када клијент пријави излаз.

Узмите проверу започету током везе A. Тунел падне, почне веза B, а затим стигне A-ов одложени HTTP успех. Без заштите, тај стари резултат чини приказ зеленим док се B још аутентификује. Отказивање смањује узалудан рад, а генерацијска провера је оно што спречава да застарели завршетак постане тренутно стање:

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

Примените исто правило око UI диспечинга, јер маршалирано ажурирање може стићи након што је генерација отишла даље.

Иницијализација и поновно повезивање су један животни циклус

Третирајте прво повезивање, поновно повезивање и губитак канала као један животни циклус с једним скупом правила:

  • Прочитајте тренутно стање и претплатите се на обавештења у једном кораку где интерфејс то дозвољава.
  • Означите свако посматрање идентитетом везе и генерацијом.
  • Поништите спремност при поновном повезивању, излазу или изгубљеном каналу посматрања.
  • Проверите приватни ресурс тек након што власник пријави да је иницијализација завршена.
  • Објављујте само резултате који још припадају тренутној генерацији.

Изгубљен канал значи непознато, а не прекинуто. Пријављивање непознатог је искреније од пријављивања прекида који не можете да докажете, и спречава логику поновних покушаја да делује на претпоставку.

Пријавите доказе, не boolean

Вратите назначено стање сесије и спремност ресурса као одвојене вредности, сваку са старошћу. Потрошач који мора нешто да одлучи тада види да последња успешна провера има четрдесет секунди, што је другачија информација од свеже.

Тражење јавне IP адресе није доказ да је приватни API користио потребну руту, зато то не представљајте као да јесте.

Држите спровођење изван посматрача

Повратни позив се извршава након чињенице. Не може да гарантује да између догађаја и руковаоца није изашао ниједан пакет са машине. Ако дизајн захтева блокирање, мрежна политика то мора да обезбеди, а задатак посматрача је да објасни доказе свом позиваоцу. Мешање двоје ствара код који мисли да је firewall јер држи boolean. Држите слој спровођења досадним и тестабилним, а посматрач нека остане читалац.

Тада UI питање постаје једноставно: покажите шта је познато, са његовом старошћу, и реците непознато када то јесте.

Повезани чланци