/* * Copyright (c) 2026 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System.Threading; using Stateless; namespace ProtonVPN.Service.StateMachine; internal sealed partial class VpnConnectionStateMachine { private readonly StateMachine.TriggerWithParameters _connectTrigger; private readonly StateMachine.TriggerWithParameters _availabilitySucceededTrigger; private readonly StateMachine.TriggerWithParameters _endpointSelectionFailedTrigger; private readonly StateMachine.TriggerWithParameters _endpointSelectedTrigger; private readonly StateMachine.TriggerWithParameters _clientSecretKeyChangedTrigger; private readonly StateMachine.TriggerWithParameters _localAgentConnectionRequestedTrigger; private readonly StateMachine.TriggerWithParameters _connectionCertificateChangedTrigger; private void Configure() { _machine.Configure(State.Disconnected) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck) .PermitReentry(Trigger.DisconnectedReported) .Ignore(Trigger.DisconnectRequested); _machine.Configure(State.AvailabilityCheck) .OnEntryFromAsync(_connectTrigger, StartAvailabilityCheckAsync) .PermitReentry(Trigger.ConnectRequested) .Permit(Trigger.AvailabilitySucceeded, State.SelectingEndpoint) .Permit(Trigger.AvailabilityFailed, State.Disconnected) .Permit(Trigger.DisconnectRequested, State.Disconnected); _machine.Configure(State.SelectingEndpoint) .OnEntryFromAsync(_availabilitySucceededTrigger, StartSelectingEndpointAsync) .OnEntryFromAsync(_endpointSelectionFailedTrigger, StartSelectingEndpointAsync) .PermitReentry(Trigger.EndpointSelectionFailed) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck) .Permit(Trigger.DisconnectRequested, State.Disconnected) .Permit(Trigger.EndpointSelected, State.EstablishingTunnel); _machine.Configure(State.EstablishingTunnel) .OnEntryFromAsync(_endpointSelectedTrigger, EstablishTunnelAsync) .OnEntryFromAsync(_clientSecretKeyChangedTrigger, EstablishTunnelAsync) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck) .Permit(Trigger.DisconnectRequested, State.Disconnected) .Permit(Trigger.LocalAgentConnectionRequested, State.EstablishingLocalAgentChannel) .Permit(Trigger.ConnectedToGuestHole, State.Connected); _machine.Configure(State.EstablishingLocalAgentChannel) .OnEntryFromAsync(_localAgentConnectionRequestedTrigger, (ct, transition) => EstablishLocalAgentChannelAsync(transition, ct)) .OnEntryFromAsync(_connectionCertificateChangedTrigger, (ct, transition) => EstablishLocalAgentChannelAsync(transition, ct)) .Permit(Trigger.DisconnectRequested, State.Disconnected) .Permit(Trigger.RequireCertificateUpdate, State.ActionRequired) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck) .Permit(Trigger.TwoFactorRequested, State.ActionRequired) .Permit(Trigger.LocalAgentReceivedConnectedState, State.Connected); _machine.Configure(State.Connected) .OnEntry(OnConnected) .OnExit(OnExitConnectedState) .Permit(Trigger.DisconnectRequested, State.Disconnected) .Permit(Trigger.ConnectionCertificateChanged, State.EstablishingLocalAgentChannel) .Permit(Trigger.RequireCertificateUpdate, State.ActionRequired) .Permit(Trigger.ClientSecretKeyChanged, State.EstablishingTunnel) .Permit(Trigger.TwoFactorRequested, State.ActionRequired) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck); _machine.Configure(State.ActionRequired) .Permit(Trigger.ConnectRequested, State.AvailabilityCheck) .Permit(Trigger.DisconnectRequested, State.Disconnected) .Permit(Trigger.LocalAgentReceivedConnectedState, State.Connected) .Permit(Trigger.ConnectionCertificateChanged, State.EstablishingLocalAgentChannel); } }