/*
* 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.Observers;
using ProtonVPN.Client.Contracts.Messages;
using ProtonVPN.Client.EventMessaging.Contracts;
using ProtonVPN.Client.Logic.Connection.Contracts;
using ProtonVPN.Client.Logic.Connection.Contracts.Messages;
using ProtonVPN.Client.Logic.Profiles.Contracts.Messages;
using ProtonVPN.Client.Logic.Profiles.Contracts.Models;
using ProtonVPN.Client.Logic.Services.Contracts;
using ProtonVPN.Client.Settings.Contracts;
using ProtonVPN.Client.Settings.Contracts.Messages;
using ProtonVPN.Common.Core.Extensions;
using ProtonVPN.Configurations.Contracts;
using ProtonVPN.IssueReporting.Contracts;
using ProtonVPN.Logging.Contracts;
using ProtonVPN.Logging.Contracts.Events.AppLogs;
using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield;
namespace ProtonVPN.Client.Logic.Connection;
public class NetShieldStatsObserver : PollingObserverBase,
INetShieldStatsObserver,
IEventMessageReceiver,
IEventMessageReceiver,
IEventMessageReceiver,
IEventMessageReceiver,
IEventMessageReceiver
{
private const int TIMER_INTERVAL_IN_SECONDS = 20;
private const int MINIMUM_REQUEST_TIMEOUT_IN_SECONDS = 20;
private readonly ILogger _logger;
private readonly IVpnServiceCaller _vpnServiceCaller;
private readonly ISettings _settings;
private readonly IEventMessageSender _eventMessageSender;
private readonly IConnectionManager _connectionManager;
private readonly TimeSpan _requestTimeout;
private readonly object _lock = new();
private DateTime _nextRequestDateUtc = DateTime.MinValue;
private bool _isMainWindowVisible;
protected override TimeSpan PollingInterval => TimeSpan.FromSeconds(TIMER_INTERVAL_IN_SECONDS);
public NetShieldStatsObserver(ILogger logger,
IIssueReporter issuesIssueReporter,
IVpnServiceCaller vpnServiceCaller,
ISettings settings,
IEventMessageSender eventMessageSender,
IConfiguration config,
IConnectionManager connectionManager)
: base(logger, issuesIssueReporter)
{
_logger = logger;
_vpnServiceCaller = vpnServiceCaller;
_settings = settings;
_eventMessageSender = eventMessageSender;
_connectionManager = connectionManager;
TimeSpan requestInterval = config.NetShieldStatisticRequestInterval;
TimeSpan minimumRequestTimeout = TimeSpan.FromSeconds(MINIMUM_REQUEST_TIMEOUT_IN_SECONDS);
_requestTimeout = TimeSpanExtensions.Max(requestInterval, minimumRequestTimeout);
_logger.Info($"NetShield Stats - Request timeout set to {_requestTimeout}.");
}
public void Receive(ConnectionStatusChangedMessage message)
{
InvalidateTimer();
}
public void Receive(SettingChangedMessage message)
{
if (message.PropertyName == nameof(ISettings.IsNetShieldEnabled))
{
InvalidateTimer();
}
}
public void Receive(NetShieldStatisticIpcEntity message)
{
_eventMessageSender.Send(new NetShieldStatsChangedMessage
{
NumOfMaliciousUrlsBlocked = message.NumOfMaliciousUrlsBlocked,
NumOfAdvertisementUrlsBlocked = message.NumOfAdvertisementUrlsBlocked,
NumOfTrackingUrlsBlocked = message.NumOfTrackingUrlsBlocked,
NumOfAdultContentUrlsBlocked = message.NumOfAdultContentUrlsBlocked,
});
}
public void Receive(MainWindowVisibilityChangedMessage message)
{
_isMainWindowVisible = message.IsMainWindowVisible;
InvalidateTimer();
}
public void Receive(ProfilesChangedMessage message)
{
if (_connectionManager.IsConnected)
{
InvalidateTimer();
}
}
protected override async Task OnTriggerAsync()
{
DateTime utcNow = DateTime.UtcNow;
if (CanRequestNetShieldStats() && _nextRequestDateUtc <= utcNow)
{
_nextRequestDateUtc = utcNow + _requestTimeout;
_logger.Debug("NetShield Stats - Request made");
await _vpnServiceCaller.RequestNetShieldStatsAsync();
}
}
private bool CanRequestNetShieldStats()
{
return _isMainWindowVisible && _connectionManager.IsConnected && IsNetShieldEnabled();
}
private bool IsNetShieldEnabled()
{
return _connectionManager.CurrentConnectionIntent is IConnectionProfile profile
? profile.Settings.IsNetShieldEnabled
: _settings.IsNetShieldEnabled;
}
private void InvalidateTimer()
{
lock (_lock)
{
if (CanRequestNetShieldStats())
{
TriggerAndStartTimer();
}
else
{
StopTimer();
}
}
}
}