Ваша праграма працягвае працаваць, пакуль тунель памірае. 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 становіцца простым: пакажыце тое, што вядома, з яго ўзростам, і кажыце «невядома», калі гэта так.

Падобныя артыкулы