/*
* Copyright (c) 2023 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 ProtonVPN.Client.Common.Messages;
using ProtonVPN.Client.EventMessaging.Contracts;
using ProtonVPN.Client.Logic.Connection.Contracts;
using ProtonVPN.Logging.Contracts;
using ProtonVPN.Logging.Contracts.Events.ConnectionLogs;
using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn;
namespace ProtonVPN.Client.Logic.Connection;
public class VpnStateIpcEntityHandler : IEventMessageReceiver,
IEventMessageReceiver
{
private readonly ILogger _logger;
private readonly IConnectionErrorHandler _connectionErrorHandler;
private readonly IInternalConnectionManager _connectionManager;
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly CancellationTokenSource _cancellationTokenSource = new();
private bool _isNetworkBlocked;
public VpnStateIpcEntityHandler(ILogger logger,
IConnectionErrorHandler connectionErrorHandler,
IInternalConnectionManager connectionManager)
{
_logger = logger;
_connectionErrorHandler = connectionErrorHandler;
_connectionManager = connectionManager;
}
public void Receive(ApplicationStoppedMessage message)
{
_cancellationTokenSource.Cancel();
}
public async void Receive(VpnStateIpcEntity message)
{
await _semaphore.WaitAsync();
try
{
await HandleAsync(message);
}
finally
{
_semaphore.Release();
}
}
private async Task HandleAsync(VpnStateIpcEntity message)
{
if (_cancellationTokenSource.IsCancellationRequested)
{
return;
}
ConnectionErrorHandlerResult connectionErrorHandlerResponse = await _connectionErrorHandler.HandleAsync(message);
if (((message.Error != VpnErrorTypeIpcEntity.None && connectionErrorHandlerResponse == ConnectionErrorHandlerResult.SameAsLast) ||
(message.Error == VpnErrorTypeIpcEntity.NoneKeepEnabledKillSwitch && message.Status == VpnStatusIpcEntity.Disconnected)) && message.NetworkBlocked == _isNetworkBlocked)
{
_logger.Info($"Ignoring VPN state with Status '{message.Status}' " +
$"and Error '{message.Error}' handled with '{connectionErrorHandlerResponse}'.");
return;
}
_isNetworkBlocked = message.NetworkBlocked;
LogHandlerResponse(message, connectionErrorHandlerResponse);
if (connectionErrorHandlerResponse == ConnectionErrorHandlerResult.Reconnecting)
{
_logger.Info($"Changing VPN state from Status " +
$"'{message.Status}' to '{VpnStatusIpcEntity.Reconnecting}'.");
message.Status = VpnStatusIpcEntity.Reconnecting;
}
await _connectionManager.HandleAsync(message);
}
private void LogHandlerResponse(VpnStateIpcEntity message,
ConnectionErrorHandlerResult connectionErrorHandlerResponse)
{
string logMessage = $"The VPN state with Status '{message.Status}' and " +
$"Error '{message.Error}' was handled with '{connectionErrorHandlerResponse}'.";
if (connectionErrorHandlerResponse == ConnectionErrorHandlerResult.SameAsLast)
{
_logger.Debug(logMessage);
}
else
{
_logger.Info(logMessage);
}
}
}